rubrapack Manual←↑→

29 Windows folders and environment variables

A package names places on a PC its author has never seen: "the program files folder", "this user's settings folder", "the Windows folder". On one PC the program files folder is C:\Program Files, on another D:\Program Files; the user is called someone different on each. This chapter explains how Windows names such places - environment variables, known folders and Windows Installer's folder properties - and when each name is turned into a real path.

29.1 What an environment variable is#

Every running program carries a small list of environment variables: names with text values, such as TEMP=C:\Users\<name>\AppData\Local\Temp. A program gets a copy of the list from the program that started it; changing its copy changes nothing for anyone else. Names are not case-sensitive: %TEMP%, %Temp% and %temp% are the same variable.

Each tool writes them its own way:

WhereHow a variable is written
Command Prompt (cmd.exe), batch files%TEMP%
PowerShell$env:TEMP
A registry value of type REG_EXPAND_SZ, a shortcut's target%TEMP%, replaced when the value is read
A Windows Installer formatted string[%TEMP], replaced during installation

Where the list comes from: when a user logs on, Windows builds it from

A change to the stored variables reaches only programs started afterwards. A package that sets a variable ([env.*], tutorial chapter 11) therefore asks for a new Command Prompt before it is seen.

29.2 The common variables#

Typical values on Windows 10 and 11 on drive C:; <name> is the user's account name.

Folders#

VariableTypical valueNotes
SystemDriveC:the drive Windows started from; no backslash
SystemRootC:\Windowsthe Windows folder
windirC:\Windowsthe older name for the same folder
ProgramFilesC:\Program Filesin a 32-bit program on 64-bit Windows: C:\Program Files (x86)
ProgramFiles(x86)C:\Program Files (x86)64-bit Windows only
ProgramW6432C:\Program Files64-bit Windows only; the 64-bit folder, also for a 32-bit program
CommonProgramFilesC:\Program Files\Common Filesshared parts of several programs; (x86) and W6432 forms as above
ProgramDataC:\ProgramDatadata shared by all users
ALLUSERSPROFILEC:\ProgramDatathe older name for the same folder
PUBLICC:\Users\Publicfiles every user may see
USERPROFILEC:\Users\<name>the user's profile folder
HOMEDRIVE, HOMEPATHC:, \Users\<name>the user's home, in two parts; in a domain it may be a network share (HOMESHARE)
APPDATAC:\Users\<name>\AppData\Roamingsettings that travel with a roaming profile
LOCALAPPDATAC:\Users\<name>\AppData\Localsettings and caches of this PC only
TEMP, TMPC:\Users\<name>\AppData\Local\Temptemporary files; for services C:\Windows\Temp

Older guides give paths such as C:\Documents and Settings\<name>\Application Data: those are Windows XP's. Since Windows Vista the profiles are under C:\Users, and ALLUSERSPROFILE became C:\ProgramData.

The two Program Files folders are why a 32-bit program asked for %ProgramFiles% gets C:\Program Files (x86): Windows gives each kind of program the folder of its own kind.

Not folders#

VariableTypical valueNotes
USERNAME<name>the account's name
USERDOMAINOFFICE, or the PC's namethe domain of the account; the computer's name for a local account
LOGONSERVER\\DC01, or \\ and the PC's namethe computer that checked the password
COMPUTERNAMEDESKTOP-1A2B3Cthis PC's name
ComSpecC:\Windows\system32\cmd.exethe command interpreter
PathC:\Windows\system32;C:\Windows;...folders searched for a program typed without a folder, separated by ;
PATHEXT.COM;.EXE;.BAT;.CMD;...the extensions tried when a program is typed without one
OSWindows_NT
PROCESSOR_ARCHITECTUREAMD64, ARM64 or x86x86 in a 32-bit program, which finds the real one in PROCESSOR_ARCHITEW6432
NUMBER_OF_PROCESSORS8

The Command Prompt also answers %CD%, %DATE%, %TIME%, %RANDOM% and %ERRORLEVEL%, but it makes them up when asked; they are not in the environment, and nothing else sees them.

29.3 Folders without a variable#

The desktop, the Start menu and its Programs folder, the Startup folder, the Fonts folder and Documents have no environment variable. Windows names them as known folders, and a program asks for one with SHGetKnownFolderPath. That is also the reliable way for the folders that do have a variable: whoever starts a program can give it any environment, and a user may have moved Documents or the desktop elsewhere (into OneDrive, for example), which only the known folder reflects.

29.4 Three moments#

A name becomes a path at one of three moments, and the moment decides whose path it is.

  1. Build time, on the machine that runs rubrapack build. Nothing about the target PC is known yet. rubrapack's $(NAME) variables are replaced here; they never read the build machine's environment (pass a value with -D NAME=value).
  2. Install time, on the target PC. Windows Installer works out its folder properties and the [%NAME] parts of formatted strings, for the user who installs. In a per-machine package installed by an administrator, the "local application data" folder is the administrator's.
  3. Run time, whenever a program reads the value. A REG_EXPAND_SZ value holding %LOCALAPPDATA%\Hello\log gives every user their own folder, because each user's program expands it with that user's environment.

So a log folder for each user is written for run time:

[registry.LogDir]
root = "HKLM"
key = 'SOFTWARE\Example Software\Hello'
name = "LogDir"
type = "expand"
value = '%LOCALAPPDATA%\Hello\log'        # expanded by each user's program

whereas value = '[LocalAppDataFolder]Hello\log' would store the installing user's folder for everybody.

29.5 Windows Installer's names#

Windows Installer has its own property for most folders, worked out at install time:

VariableWindows Installer property
ProgramFilesProgramFiles64Folder in a 64-bit package, ProgramFilesFolder in a 32-bit one
ProgramFiles(x86)ProgramFilesFolder
CommonProgramFilesCommonFiles64Folder / CommonFilesFolder
ProgramData, ALLUSERSPROFILECommonAppDataFolder
APPDATAAppDataFolder
LOCALAPPDATALocalAppDataFolder
TEMPTempFolder
SystemRoot, windirWindowsFolder
SystemDriveWindowsVolume (with a backslash: C:\)
(System32)System64Folder in a 64-bit package; SystemFolder is the 32-bit system folder
USERNAMELogonUser
COMPUTERNAMEComputerName

Every folder property ends in a backslash, so [ProgramFiles64Folder]Hello needs none between. Beware of USERNAME: Windows Installer's property of that name is the name typed for registration, not the account; the account is LogonUser. Any variable without a property is reached as [%NAME].

29.6 In rubrapack#

rubrapack writes all these names one way, $(NAME), with Windows' spelling (letter case does not matter); $$ is a literal $. When the name is replaced depends on where it stands:

So the log folder for each user from above is written

[registry.LogDir]
root = "HKLM"
key = 'SOFTWARE\Example Software\Hello'
name = "LogDir"
type = "expand"
value = '$(LOCALAPPDATA)\Hello\log'       # stored as %LOCALAPPDATA%\Hello\log

and without type = "expand" the same value would store the installing user's folder. The table of every name and what it becomes is in the Reference part (Windows names). An MSIX has no install time: a value that needs one is refused there (RP1612), while the run-time form works, since the program expands it.

29.7 Where this is used#