rubrapack Manual←↑→

12 Services, fonts, permissions

Goal: install a background service that starts by itself, a font every program can use, and a data folder whose access rights you set - the three things only a per-machine package may do.

12.1 The source#

dist\hellosvc.exe is the service program, dist\HelloSans.ttf a font file.

# tutorial 12: hello.toml
format = 1

[package]
name = "Hello"
manufacturer = "Example Software"
version = "$(VERSION)"
arch = "x64"
upgrade-code = "{3F2A6C1D-8B4E-4F7A-9C2D-5E6F7A8B9C0D}"
reboot = "suppress"

[define]
VERSION = "1.10.0"

[dir.INSTALLDIR]
path = "$(ProgramFiles)/Hello"

[dir.DataDir]
path = "$(ProgramData)/Hello"

[dir.FontsDir]
path = "$(Fonts)"

[file.Hello]
dir = "INSTALLDIR"
source = "dist/hello.exe"

[file.Service]
dir = "INSTALLDIR"
source = "dist/hellosvc.exe"

[file.Font]
dir = "FontsDir"
source = "dist/HelloSans.ttf"

[service.HelloService]
file = "file:Service"
name = "HelloService"
display-name = "Hello background service"
description = "Keeps Hello's greetings up to date."
start = "auto"
account = "LocalService"
args = "--service"
start-on-install = true

[font.HelloSans]
file = "file:Font"
title = "Hello Sans"

[permission.DataFolder]
target = "dir:DataDir"
sddl = "D:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1301bf;;;BU)"

12.2 A service: [service.ID]#

A service is a program Windows runs in the background, without a window, often before anyone signs in (the Services console, services.msc, lists them).

KeyMeaning
filethe service's program: file: and a [file.*] ID
namethe service's internal name (used by sc start HelloService)
display-name, descriptionwhat the Services console shows
startauto (at every start of Windows), demand (when something starts it), disabled
accountwho it runs as: LocalSystem (full rights), LocalService (few rights - prefer it), NetworkService
argsits command-line arguments
start-on-install = truestart it at the end of the installation

The installer stops the service before its files are replaced (in an upgrade or a repair) and at removal, and deletes it at removal. The program must really be a service - one that answers Windows' service manager; an ordinary program would make the start fail, and with it the installation.

12.3 A font: [font.ID]#

A font is installed by putting its file into the Fonts folder - [dir.FontsDir] with path = "$(Fonts)", the folder alone - and registering it with [font.ID]. title is the name Windows lists; without it Windows reads the name from the font file. Every program sees the font after the installation; removal unregisters and deletes it.

12.4 Access rights: [permission.ID]#

Every file, folder and registry key in Windows has an access list saying who may read or change it. [permission.ID] sets that list, written in SDDL (Security Descriptor Definition Language), on a folder the package creates (dir:ID), one of its files (file:ID) or a registry value it writes (registry:ID). A folder given a permission is created even without files in it.

The SDDL string above, piece by piece:

PieceMeaning
D:the access list (DACL) follows
PAIprotected (do not inherit from the parent folder), and passed on to what is inside
(A;OICI;FA;;;SY)Allow, to files and sub folders (Object and Container Inherit), Full Access, to SYSTEM
(A;OICI;FA;;;BA)the same for the Built-in Administrators
(A;OICI;0x1301bf;;;BU)Built-in Users may read, write and delete, but not change the rights

So C:\ProgramData\Hello is writable by every user, but only administrators may change who may. Get a string for a folder you set up by hand with icacls or PowerShell's (Get-Acl C:\path).Sddl.

12.5 Programs that are still running: the preflight#

Before it changes anything, the package looks which programs use the product's files - the product's own programs, and programs that have one of its DLLs loaded - and asks whether to close them all (Yes closes them, No goes on without closing, Cancel stops). Without a window (/qn) it stops with an error instead, unless the command line says RPCLOSE=yes or RPCLOSE=no:

C:\work\hello> msiexec /i hello-2.0.0.msi /qn RPCLOSE=yes

close-programs = "always" or "never" in [package] fixes the answer - "never" for an input method or a shell extension, which nearly every open program has loaded - and preflight = false leaves the step out (the reference, "Before it goes on", has the other checks).

12.6 Restarting: reboot#

Sometimes a file cannot be replaced until Windows restarts. reboot = "suppress" (the default) never restarts by itself: the installation ends with exit code 3010 ("restart needed") and the user restarts later. reboot = "allow" lets Windows Installer ask for, or at /qn perform, a restart when one is needed.

What waits for the restart is usually a file a running program still holds. The package's cleanup task deletes it earlier - as soon as that program closes - and then itself; cleanup = false in [package] leaves the task out (see the reference, "Cleaning up later").

12.7 Try it#

Install (as administrator), then: services.msc lists "Hello background service", running; a text editor offers the font "Hello Sans"; the Security tab of C:\ProgramData\Hello shows the three entries. Remove Hello: the service, the font and the folder are gone.

12.8 What happened inside#

C:\work\hello> rubrapack inspect hello.msi ServiceInstall
HelloService	HelloService	Hello background service	16	2	1			NT AUTHORITY\LocalService		--service	C_d677...	Keeps Hello's greetings up to date.
C:\work\hello> rubrapack inspect hello.msi ServiceControl
HelloService	HelloService	163		1	C_d677...

16 is "a service in its own process", 2 "automatic start", 1 "report errors normally". The 163 in ServiceControl is a sum of bit flags: 1 (start at install) + 2 (stop at install) + 32 (stop at removal) + 128 (delete at removal). Bit flags in Part III explains how such sums work. A package with permissions declares Windows Installer 5.0 (the summary's schema, 14 500 in rubrapack inspect hello.msi --summary), because the MsiLockPermissionsEx table is newer than the rest.