Barvna shema: Riviera
Trenutno dejavna stran: start » en » Documentation » Microsoft Access development tools » WKL Bootstrapper » Reference » The installer of the bootstrapper 2.0

The installer of the bootstrapper 2.0

From 2.0 the starter installs an application for the Windows user the way Windows Installer installs a package per user: from a description of what it consists of, as one transaction that is rolled back on failure, with every shared part counted, so that update, going back, repair and uninstall leave exactly the state they promise. Nothing needs administrator rights.

When 2.0 installs and when 1.0 runs

DeliveryWay
A project file of format 2 (any program or file; see The project file)Installer of 2.0, general project
The components folder of the delivery contains registration.json next to the DLL (release packages of WKL Forms Object Library from 1.57), or the delivery brings no components (components empty)Installer of 2.0 (this page)
Components delivered without registration.json (packages up to 1.56.1)As 1.0

registration.json is the per-user registration of the DLL as data, written when the package is built (tools\Export-Registration.ps1 of WKL Forms Object Library). The starter writes these keys itself instead of running regsvr32; Windows Installer advises against self-registration because it cannot be rolled back safely and hides what it writes.

What is installed, and where it is recorded

Each part of an installed version is a component with a key path; the component is installed when its key path exists. Every product version that uses a component is one of its clients - the reference count.

Component (id)WhatKey path
frontend/<product>/<version>The copy of the application in %LOCALAPPDATA%\WKL\<product>\Frontends\<version>, the whole folder (also files Access or the application leave there), and the INI of iniThe database file
components/<release>/<bitness>The WKL components of one release and bitness in %LOCALAPPDATA%\WKL\Components\<release>\<bitness> and their registration below HKCU\Software\Classes (32-bit view for x86)The DLL
odbc/<driver>/<release>/<bitness>An ODBC driver the delivery brings, in %LOCALAPPDATA%\WKL\Drivers\<driver>\<release>\<bitness>, and its data source for the user (see ODBC drivers)The driver DLL
trust/<product>The trusted location WKL.<product> (see What the starter writes and reports)The key
apps-entry/<product>The entry under Windows Settings > Apps: HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\WKL.<product> with DisplayName, DisplayVersion, Publisher, UninstallString ("<starter>" /uninstall), QuietUninstallString, DisplayIcon, InstallDate, NoModify, NoRepairThe key

The record is the installer database of the user, %LOCALAPPDATA%\WKL\Installer\installer.db (SQLite, the copy of SQLite that Windows ships; one database for all products of the user). Its tables:

TableContent
ProductProduct key, display name, source
ProductVersionInstalled versions, State (installed/removed), LastWorking (the version started last)
ComponentId, kind, release, bitness, key path
ComponentClientWhich product version uses which component
ResourceEvery file, folder, registry key and value of a component, with Ownership: created (by the starter; removed with the last client) or found (was there before; never removed, put back to Previous)
Txn, TxnStepThe journal: each operation, each step with its undo information

How to check it from outside.

  • Wkl.Bootstrapper.exe /list prints every installed version and every component with its number of users; a component whose key path is missing is marked MISSING (repair: /repair). /list /json prints the same as JSON (see Commands and exit codes).
  • The database can be read with any SQLite tool, for example SELECT * FROM ComponentClient. Read only: the starter is the only writer.
  • The log of the product (Logs\bootstrapper.log) has one line per step: date and time with milliseconds, the process id, the step padded to 12 characters, then the text. Per install it writes a line with the step install: for a delivery of format 1 install <version> <copy>, followed by components <release> when components were registered; for a project of format 2 install <product> <version>: <n> entries, <n> registry keys. A delivery that uses an existing registration writes components using the existing registration ... instead.

Install and update

A start with a new version (or the first start) runs these steps as one transaction:

  1. An interrupted earlier transaction is rolled back first (the PC went off, the process was ended).
  2. On the first meeting with the product, what the starter 1.0 installed is taken over (see below).
  3. The version is recorded.
  4. The copy is placed - unless it exists: copied, checked against size and SHA-256 of app-manifest.json (code 42 when it differs), the mark of the web removed; the INI written.
  5. The components: an existing registration the starter did not make (the IT's for the computer, HKLM, or the release package's own for the user) that points at an existing DLL of a release at least as high as the application requires (requires of app-manifest.json) is used as it is - registering again would double it, and COM would take the user's registration before a newer one of the computer. Otherwise the release rule decides; a release folder to be registered is copied (only missing files; a DLL in use is never replaced) and the registration written from registration.json.
  6. The ODBC drivers of the delivery, each with its data source (see ODBC drivers).
  7. The trusted location and the entry under Apps are written or updated (DisplayVersion).
  8. The transaction is committed.

Afterwards, in a transaction of its own, versions beyond keepVersions are removed (never the version being started and never the last working one), and then Access starts. A version started successfully becomes the last working one.

On failure every step done so far is undone in reverse order, the PC is as before the start, and the window reports the code:

CodeCause
11registration.json is not a registration table
32The delivered release is older than the application needs (and no sufficient registration exists)
41A file could not be copied, moved or removed; when another program holds it, the message names it (for example a virus scanner)
42The copy does not match the manifest
50A policy forbids trusted locations of the user

File steps wait and try again for a moment while another program (a virus scanner, the indexer) holds a file.

Example: the IT registered the components for the computer. WKL Forms Object Library 1.56 is registered below HKLM with the DLL in C:\Program Files (x86)\WKL\Access Components, the application requires 1.51, and the delivery brings 1.56.1. The starter registers nothing, copies no components and records no components/... component; the log has the line components using the existing registration 1.56 for the computer: C:\Program Files (x86)\WKL\Access Components\Wkl.Access.Components.dll. Were the registration for the computer 1.48, the delivered 1.56.1 would be registered for the user, and the user's registration would win over the computer's from then on.

Which release is registered

One release of WKL Forms Object Library is registered per user and bitness at a time: the class keys are the same in every release, so the last registration decides for every application of the user. Each product version records the release its application requires (requires in app-manifest.json). The starter registers the delivered release unless that would take a release away from another product:

Delivered releaseRegistered release (by the starter)Result
Lower than the application requiresAnyCode 32; nothing changes
At least what the application requiresNone, or lower than the application requiresThe delivered release is registered
Higher than the registered releaseAt least what the application requiresThe delivered release is registered
The same as the registered releaseThe sameNothing changes; the product version becomes one more client
Lower than the registered releaseAt least what the application requiresThe delivered release is registered if no installed version of another product requires more than it; otherwise the registered release stays and the product version becomes one more client of it

Only other products count. Versions of the same product kept beside the started one (keepVersions) do not: going back within a product registers the release that version was delivered with, and going forward registers the newer one again. Example: product A 1.4.0 requires 1.56 and was delivered with 1.56.1, A 1.5.0 requires 1.57 and was delivered with 1.57.0.

StartRegistered afterwards
A 1.5.01.57.0
A 1.4.0 (going back), no other product installed1.56.1
A 1.5.0 again1.57.0
A 1.4.0, while product B 1.0.0 requiring 1.57 is installed1.57.0 stays

Two products with different releases therefore both run on the higher one: a running Access keeps the DLL it loaded when the registration changes, and Access processes started afterwards load the newly registered release.

The release of a delivery is the release of its registration.json, which Export-Registration.ps1 takes from the product version of Wkl.Forms.ObjectLibrary.Managed.dll (up to release 1.68: Wkl.Access.Components.Managed.dll; for example 1.56.1). The version resource of the native start module (Wkl.Forms.ObjectLibrary.dll, up to 1.68 Wkl.Access.Components.dll) carries only major and minor (1.56.0 in 1.56.1) and is not used; the starter 1.0 used it, so its folders below Components may carry that number.

ODBC drivers

A delivery may bring ODBC drivers for the user, so that no administrator has to install them. Each driver lies in the delivery as odbc\<driver>\x86 and odbc\<driver>\x64 and is named in bootstrapper.json:

{
  "format": 1,
  "product": "Customers",
  "source": "\\\\server\\apps\\kunden\\production",
  "components": "components",
  "odbcDataSources": [ "WklGateway" ],
  "odbc": [
    { "driver": "Wkl OData", "folder": "odbc\\Wkl OData", "dll": "Wkl.Data.OData.Odbc.dll", "dataSource": "WklGateway" }
  ]
}
FieldMeaning
driverThe driver's name; also the folder below %LOCALAPPDATA%\WKL\Drivers and the value in ODBC Data Sources
folderThe folder of the driver in the delivery, relative to source; the starter takes the subfolder of the bitness of Access
dllThe driver DLL in that subfolder
dataSourceThe user data source the application connects through

The starter copies the subfolder to %LOCALAPPDATA%\WKL\Drivers\<driver>\<release>\<bitness>, where <release> is the product version of the DLL without a build id, and writes the data source for the user (32-bit view of the registry for x86):

KeyValueData
HKCU\Software\ODBC\ODBC.INI\<dataSource>DriverThe full path of the copied DLL
Description<driver> (Wkl.Bootstrapper)
HKCU\Software\ODBC\ODBC.INI\ODBC Data Sources<dataSource><driver>

No ODBCINST.INI entry is written; Access opens linked tables and pass-through queries through a data source whose Driver is the path of the DLL. Everything else - the service address, the database - belongs into the connection string of the application's links, not into the data source. A data source named in odbc is not required to exist before the start, unlike the other entries of odbcDataSources.

The driver is a counted component like the WKL components: a newer release delivered later is placed beside the old one and the data source points to it; an uninstall removes the release folder and the data source with the last product version using them. A data source of that name that existed before the starter wrote it is put back to its previous values.

Unlike the WKL components, the data source follows no release rule: every start writes it for the version started. Going back to a version delivered with an older driver release points the data source at that older release again. When two products deliver the same dataSource with different driver releases, the product started last decides; no code is reported, and both release folders stay as long as a version uses them. Give each product its own dataSource when they must not share a driver release.

Going back

Starting an older version - a source that delivers a lower version again - installs that version again: its copy (if it is still there), its drivers (the data source points at the older driver release again) and its components release under the release rule. Newer versions stay until keepVersions or the uninstall removes them, so the user can go forward again.

With deliveryKey in the project file, a source delivers a lower version only when the publisher withdrew the higher one in the signed delivery (/publish /withdraw); otherwise the starter keeps the installed version and reports code 52. See How to: Publish a signed delivery.

Going back while the source already delivers a newer version works from the settings window (Wkl.Bootstrapper.exe /settings). Its three actions run on the installer, each as one transaction with its rollback:

ActionWhat it does
Start this versionRegisters again what the chosen version ran on: its WKL components release (from the installed release folder, under the release rule) and its data sources. Then it starts Access with that version's copy and marks it as the last working version, which the cleanup keeps. Nothing is copied from the source.
Copy againRemoves the chosen version with every component only it used. The next start installs the version the source delivers again. Refused at once while Access has the copy open.
Remove old versionsRemoves the versions beyond keepVersions, as a start does. It never removes the version the source delivers or the last working version.

Start this version brings back the components release the version used, not the one its delivery contained. A version that stayed on a newer release because another product needed it stays on that newer release.

A product that only the bootstrapper 1.0 placed keeps the 1.0 actions on its folders until its next start takes it over.

Repair

Wkl.Bootstrapper.exe /repair runs the install of the current version without starting Access: whatever is missing is put back from the delivery - the copy if deleted, files of the components, registry values that were deleted or changed, the trusted location, the entry under Apps. What is in place is not touched; an existing copy keeps the user's data.

Uninstall

Wkl.Bootstrapper.exe /uninstall (also the command Windows runs from Settings > Apps) removes, as one transaction:

  • every version of the product: the version folders with everything in them;
  • every component no other product version of the user still uses: files, folders, and registry keys and values the starter created;
  • registry values that existed before the starter wrote them are put back to their previous content, never deleted;
  • the trusted location and the entry under Apps.

Components another product of the user still uses stay, and with them the class keys they share; when the removed product used the registered release, the newest remaining release of the same bitness is registered again. When a copy is open in Access, nothing is removed and the code is 41 with the program named; close Access and run it again.

The shortcuts of the project's shortcuts list are removed with the product, also those whose target is the starter itself.

Not touched: the folder the starter runs from with its bootstrapper.json, shortcuts that do not come from the project, the installer database itself and the logs below %LOCALAPPDATA%\WKL\<product>\Logs.

Commands and exit codes

CommandDoesExit code
(none)Installs or updates, then starts AccessThe code of the run; 0 when Access started
/quietThe same without any windowAs above
/repairInstalls what is missing, does not start AccessThe code of the run; 0 when complete
/uninstall [/quiet]Removes the product of the bootstrapper.json next to the EXE. Without /quiet (the entry under Windows „Apps“) the starter first asks in its window, in the language and color scheme of the project; Cancel is the default button, so Enter, Esc and closing the window keep everything. With /quiet (scripts, QuietUninstallString) it removes without a question0 removed; 1602 canceled, nothing removed (the code of msiexec); 10 bootstrapper.json missing; 41 in use or failed (rolled back); 43 a beforeUninstall action failed (nothing removed)
/listPrints the installed versions and components0
/list /jsonThe same as JSON0
/RUNCFG <file> with any commandUses <file> (a .json file in the starter's folder, a plain file name) instead of bootstrapper.json: several applications beside one starter. The entry under Apps uninstalls with the same switch.As the command; 10 for a name with a path
/new-key <name>Creates the publisher's delivery key in the Windows key store of the user and prints its public part for deliveryKey0; 10 the name exists
/publish [/key <name>] [/withdraw <version>[,<version>]]Writes delivery.json (and with a key delivery.json.sig) into the source of the project file; /withdraw names the higher versions this delivery replaces; see How to: Publish a signed delivery0; 11 a withdrawn version is no higher version; 12 source not reachable; 51 key missing or not the project's
/whatif <file> [/json]A dry run of the project file: every check of a start and the plan of what it would install where, without changing anything; see What the starter writes and reportsAs /diagnose: 0 when a start would succeed, else the error code
/check <file> [/json]Checks a project file against its rules and prints every problem; with /json an object with valid, format and problems. Reads only the project file: whether the delivery holds what it names (for example registration.json of the components) is checked by /whatif. From 2.3.0 a file ending in .msi.json is checked as installer settings, including the files they name0 valid; 10 file not found; 11 problems
/msi-sources <project file> /out <folder> [/starter <exe>] [/version <x.y.z>]Version 2.3.0 and later: writes the WiX sources of the starter's package from <name>.msi.json beside the project file (or of the package without dialogs when there is none) and prints, as JSON, the packages to build (builds with scope, culture, output, sources, localization; images to convert from PNG). Used by tools\New-StarterMsi.ps1; needs no WiX Toolset0 written; 10 project file, folder or starter missing; 11 a rule broken or a page that does not fit
/import-reg <file.reg> [/json]Reads a .reg file of Registry Editor into registry entries of a project (only below HKEY_CURRENT_USER; HKEY_CLASSES_ROOT becomes Software\Classes of the user, WOW6432Node the 32-bit view) and lists what was left out (keys of the computer, binary values, deletions). Writes nothing; with /json the project's registry list and notes, ASCII only0 read; 10 file not found; 11 no .reg file
/new-project <file> /template <names> [/json]Writes a new project file of format 2 from templates; <names> is a comma-separated list of access (the application of the build tool's app-manifest.json, started as it says, with the condition Microsoft Access), components (WKL Forms Object Library from components\x86 and components\x64 of the delivery folder, registered for the user, with the condition .NET 10 Desktop Runtime), odbc (an example ODBC driver with a data source of the user per bitness, to be replaced with the delivered one) and json (WKL Office JSON from json\x86 and json\x64) and dotnet (a private .NET runtime from dotnet\x86 and dotnet\x64, kept per release below [WklRoot]\Dotnet and handed to the started program as DOTNET_ROOT(x86) or DOTNET_ROOT; it replaces the condition .NET 10 Desktop Runtime of components, but only for programs the starter starts); none gives a project that starts nothing yet. The product key is the name of the file's folder, the delivery folder deploy beside the starter. Lists what is left to do; with /json an object with written, notes and problems, ASCII only0 written; 10 no file named; 11 unknown template, or the file exists
/import-starterpro <xml> [/out <file>] [/json]Converts a configuration of the former starter into a project file of format 2 (by default bootstrapper.json beside it) and lists what was not taken over; with /json an object with written, notes and problems, every character outside ASCII escaped; see How to: Move from the former starter0 written; 10 configuration not found; 11 no configuration of the former starter, or the project file exists

The codes are those of Error codes of the starter. /list /json prints one object:

{
  "versions": [
    { "product": "Customers", "displayName": "Customers", "version": "1.4.0", "lastWorking": true }
  ],
  "components": [
    { "id": "components/1.56.1/x86", "keyPath": "C:\\Users\\<user>\\AppData\\Local\\WKL\\Components\\1.56.1\\x86\\Wkl.Access.Components.dll", "clients": 2, "present": true }
  ]
}
FieldMeaning
versions[].productProduct key of bootstrapper.json
versions[].displayNameName shown under Apps
versions[].versionVersion of the application (app-manifest.json)
versions[].lastWorkingTrue for the version started successfully last
components[].idComponent id, see What is installed
components[].keyPathFile or key whose presence means installed
components[].clientsNumber of product versions using the component
components[].presentFalse when the key path is missing; /repair puts it back

With nothing installed the arrays are empty.

Testing that a failed install leaves nothing

To see a rollback on a test PC, let the copy fail after the version was recorded:

  1. Run /list /json and keep the output.
  2. Place a new version in the source and change one byte of its database file after app-manifest.json was written.
  3. Start the starter. It reports code 42.
  4. Run /list /json again: the output equals step 1, and no folder of the new version exists below Frontends.

To see that the registration of the components and the data source are taken back as well, let a step after them fail. The driver is placed after the components (step 6 after step 5), so a delivery with an odbc entry serves:

  1. Run /list /json and note the values of the components' class key (for example HKCU\Software\Classes\WklForms.Application\CLSID, up to release 1.68 WklComponents.Application, and its InprocServer32) and of HKCU\Software\ODBC\ODBC.INI\<dataSource>.
  2. Place a new version in the source whose delivery brings a newer components release and the driver.
  3. Hold the delivered driver DLL open so that it cannot be read, for example in PowerShell: $f = [System.IO.File]::Open('<source>\odbc\<driver>\x86\<dll>', 'Open', 'Read', 'None').
  4. Start the starter. After a few seconds of retrying it reports code 41.
  5. Compare: /list /json, the class key and the data source equal step 1; no folder of the new release exists below %LOCALAPPDATA%\WKL\Components or %LOCALAPPDATA%\WKL\Drivers.
  6. Release the file ($f.Dispose()) and start again: the new version installs.

A policy against trusted locations does not serve this purpose: the starter checks it before anything is installed (code 50 without a transaction), and the policy keys below HKCU\Software\Policies cannot be written without administrator rights.

To see that an uninstall does not remove half of a product, open the installed copy in Access and run /uninstall /quiet: code 41 names MSACCESS.EXE, and /list still shows every version and component.

Taking over the starter 1.0

The first time 2.0 meets a product, it records as its own what the starter 1.0 left: the version folders below Frontends (the last working version from State\provisioning.json), the trusted location 1.0 wrote (its description ends with (Wkl.Bootstrapper)), and the registration 1.0 made with regsvr32 from %LOCALAPPDATA%\WKL\Components. They are then cleaned up and uninstalled like parts placed by 2.0. Registrations from anywhere else are not taken over.

Limits of the installer

  • Two starters of the same Windows user installing at the same moment are not serialized: the installer database is one per user, and a starter that finds an unfinished installation rolls it back, also one that another starter is running. Start one at a time (format 1 without registration.json serializes per product).
  • A file of format 1 does not deliver the .NET Desktop Runtime: the starter checks it (code 33). A project of format 2 can deliver a private runtime; see How to: Deliver a private .NET runtime.
  • WKL JSON is not delivered by a format 1 file: an application that uses it needs it registered beforehand, for example by the IT. A project of format 2 delivers it as a registerCom entry like any COM server.
  • Computers that restrict programs in the user's profile with AppLocker or Windows Defender Application Control are not supported.
  • A source over HTTP/HTTPS is not supported; the source is a folder or a share.
en/wiki/msaccess/bootstrapper/reference/installer.txt · Zadnja sprememba: uporabnika Wolfgang van der Stille