WinAppMigrator

Code Map

For developers. Every source file, one line each, grouped by the stage it belongs to. The words come from each file's own //! comment where it has one. For how the crates fit together, see Project layout. For how discovery works in depth, see docs/discovery.md, and for the screens, docs/gui.md.

All paths are under crates/.

winappmigrator-core

Listing Apps

File What it does
app_inventory.rs Reads the Uninstall keys of the machine (64- and 32-bit views) and of an account into the list of installed apps, leaving out hidden entries (SystemComponent=1), and guesses each app's main program. On a drive from 32-bit Windows, which has one view, every app is 32-bit.
profile_survey.rs Which accounts on a PC or drive have data for an app, for choosing whose goes in an installer. Loads each account's registry once, when the list is read.
system_context.rs Where a scan reads from: the live PC, or a drive from another PC, whose hives it copies and loads. VolumeMap is the one place a path recorded on the other PC becomes one that can be read here. A drive is not trusted. SourceIdentity says which Windows a PC or drive has, in words, and whether it is older than 10 or 32-bit.
disk_image.rs A disk image of another PC (.vhd or .vhdx), attached read-only with no drive letter for as long as it is read, and read as a connected drive. Its volumes are mounted on folders under %ProgramData%\WinAppMigrator\images. sweep_leaked_images detaches what a run that ended without doing so left attached.

Another PC over the Network

File What it does
remote.rs Another PC, read through its client. Finds clients by asking each network this PC is on, pairs with one by its code, and gives it a root of its own, \\?\WAMLINK-<id>\, that is a ScanSource::OfflineVolume like any connected drive. No path of this PC can start with that root, and Windows refuses to open one that does. Each request waits up to two minutes for its answer.
source_fs.rs Reading what a scan and a build read: for a path of this PC or a connected drive, what std::fs does; for a path below a paired PC's root, what its client answers. A link there is never followed. So the capture is the one a drive gets, and only what it reads crosses the network.

Scanning

File What it does
scan.rs Runs a scan of one app from start to finish: folds the install record into discovery, gathers every scanner's findings, and records them in a ScanReport. Also detects runtimes from the app's programs. Writes nothing.
install_source.rs Works out how an app was installed, and reads the record that setup kept: the MSI component database, Inno Setup's unins000.dat, NSIS's uninstall.log, and App Paths.
file_discovery.rs Walks an app's folders, classifies each file (app, per-user data, machine-wide data, driver), and decides where each lands on restore. Holds the checks that keep an install or an uninstall from going through a link. With User Data, puts an account's own copies of the app's files, which Windows kept in its VirtualStore, in place of the app's (put_what_windows_kept_aside_in_place).
product_match.rs Decides from a folder or key name whether it is an app's, by whole names, never substrings. Also says what is close without being it.
near_match.rs What exact names leave out and may still be the app's, offered for a person to choose from. Never takes anything itself.
registry_scan.rs Captures the app's registry keys and values, those its install record names, Run and App Paths entries, within fixed limits. Lays an app from 32-bit Windows out as 64-bit Windows keeps a 32-bit app's (where_64_bit_windows_keeps), and, with User Data, puts what Windows kept in an account's VirtualStore in the app's own key (put_what_windows_kept_aside_in_place).
integration_scan.rs How an app is tied into Windows beyond its own keys: COM, protocols and file types, shell extensions, firewall rules, fonts, ODBC, event log sources, compatibility settings. An entry is the app's if what it points at is. Certificates are only reported.
service_scan.rs Services and drivers whose program is the app's, with their arguments and Parameters key.
task_scan.rs Scheduled tasks that run the app's programs, read from the task files themselves, on either PC.
shortcut_scan.rs The Start menu and Desktop shortcuts of the account being read and of everyone that point at the app, including, on a drive, those that name their target only with a variable, as Windows 7's own do (read_lnk_written_with_variables).
env_scan.rs Environment variables whose value holds the app's path, keeping only the app's entries of a list such as Path.
pe_scan.rs Reads a program's headers: its architecture, what it imports, its version information, and the oldest Windows it says it can run on.
dll_resolver.rs Resolves the DLLs a program imports, and tells which belong to a Visual C++ runtime or to the DirectX End-User Runtime (is_legacy_directx_dll). From a Windows older than 10, names a DLL found in its Windows folders that this PC's Windows lacks (dependency_not_in_newer_windows).
runtime_detection.rs Which runtimes an app needs, read from the main program and up to 64 others, including which .NET from runtimeconfig.json and the assembly's metadata, and whether a program needs the DirectX End-User Runtime.
license_scan.rs Finds license files, stores, variables, and registry values, and reports how likely each is tied to the machine. Never decrypts or gets around anything.
secret_rules.rs What looks like a credential, and leaving it out of a package. Pure rules, with false positives pinned by tests.
account_settings.rs What an account keeps for an app in its part of the registry, and leaving it out when User Data is off. What Windows looks in for the app, and a value saying where its folder is, go either way.
account_traces.rs What a package says of whose PC it came from, with none of an account's data in it, and the last look through a finished build.

Choosing

File What it does
footprint.rs What a scan found, as rows a person chooses from, and what comes of a choice: what else it leaves with nothing to run, in the words of the installer's list. A choice only ever takes away.

Packaging

File What it does
package.rs The build: from a scan and a person's choices to a finished installer, with the manifest, reports, licenses, drivers, and runtimes. Names the installer.
packer.rs Puts files in a package: each read once, hashed and compressed from the same bytes, on many threads, in a fixed order.
zip_stream.rs A standard zip written in one pass, so the package's SHA-256 is worked out as the bytes go out.
archive.rs The self-extracting format: stub, package, and footer, or a loader and a .wamdata data file. Reads an installer's embedded package and checks it before anything is parsed. Refuses a signed stub.
hashing.rs SHA-256 of files, and reading files back to check them.
reporting.rs The JSON and Markdown reports that go inside a package.
prerequisites.rs The compiled-in specs for each runtime: where to download it, how to install it, and how to tell it is there. Downloads at build time, installs on the target, and checks Microsoft's signature both times.
authenticode.rs Reads Authenticode signatures, through PowerShell's Get-AuthenticodeSignature.
space.rs Whether there is room for a build or an install, before either starts, always as the most it could need.

Installing

File What it does
restore_policy.rs What a package is allowed to make an elevated process do. Pure functions, each tested with a realistic case on both sides. Also whether an app's programs can run on this PC.
restore_review.rs Applies those rules to a whole package. The installer's list, the install, and verification all work from this one result. Also says why an install location cannot be used.
restore.rs The install: runtimes, files, empty folders, services, drivers, registry, firewall rules, licenses, tasks, shortcuts, environment, and the entry in Settings, each journaled first. Then verifies, and starts what starts by itself. Offers Program Files (x86) as the install location of an app from 32-bit Windows (default_install_location).
path_rewrite.rs Where a package's paths land on the target, and rewriting text in values, variables, and tasks to match, exactly.
registry_target.rs The one mapping between the registry model and the live registry, shared by restore and verify.
verify.rs Checks a finished installer, and a package as it is unpacked, against the manifest's hashes. After an install it checks what it wrote, from the same review the install used: files by hash, and registry values, services, drivers, firewall rules, variables, tasks, shortcuts, runtimes, and licenses. Writes the verification report.

Undoing

File What it does
journal.rs The record an install keeps of what it changes, in %ProgramData%\WinAppMigrator\installs\<id>, checked level by level before it is trusted. Also the lock that lets only one install or uninstall run.
rollback.rs Undoing an install from its journal: a rollback when an install fails or is cancelled, the same on the next run when one never finished, and an uninstall. Holds the folders on the way while it acts.

Shared

File What it does
lib.rs The crate's modules and what it exports.
models.rs The data types: an installed app, scan options and report, the package manifest, warnings, and the rest.
errors.rs The error type, and turning a panic into words.
progress.rs Lets a front end follow a long job and cancel it: ScanMonitor, BuildMonitor, InstallMonitor.
logging.rs Where the app and the installer write down what they did, in %ProgramData%\WinAppMigrator\logs. Paths and key names only.
path_utils.rs Path helpers, Windows' folders read from the registry, who is signed in, starting tools and PowerShell with a fixed environment, and the folder walk every scan uses, which follows no link below where it starts.
privilege.rs Whether this process is elevated, folders only administrators can change, and holding folders so they cannot become links.

Tests and Examples

File What it does
tests/log_has_no_secrets.rs Pins that a log holds paths and key names, and never what a value, license file, or variable holds; and that no credential reaches a package, and a license goes in only with the License option.
examples/wam_measure.rs Builds an installer of a real app on this PC and measures time, reads, writes, and peak disk. Installs nothing.
examples/wam_pkg.rs Builds an installer from one executable, as the app would.
examples/offline_scan.rs Lists the apps on a mounted disk. Needs an elevated shell.
examples/wam_near_matches.rs Says what near matches would be offered for every app on this PC.

winappmigrator-gui (the app)

File What it does
src/main.rs Hardens the process, then runs the app. Shows a message if the window cannot open.
src/lib.rs The app's state and its background workers: the list of apps, attaching a disk image, the scan of the selected app, what goes with a choice, how much room a drive has, and the build.
src/views.rs The screen: the header, the scan source with which Windows a drive or image has (and older_windows_note for one older than 10), the list of apps, the selected app, the output folder, the build's progress, and the result.
src/network_view.rs Network PC…: until a PC is paired, the three steps in place of the list of apps. Saves the client and its note to a USB drive or a folder, asks the network who is there every five seconds, and pairs on a worker thread.
src/footprint_view.rs The part of the screen that says what goes in the installer, before anything is built.
src/worker.rs One job at a time, on a thread of its own, and only ever the newest.
src/ui_tests.rs Drives the real screen with no window. With WAM_UI_PREVIEW_DIR set, writes a picture of each state.
src/ui_tests_footprint.rs The screen as it shows what goes in an installer, from a fake scan and the real view code.
src/ui_tests_network.rs The Network PC… steps, driven with no window, and a real pairing with the client's own code over this PC's loopback.
build.rs Embeds the elevation manifest, the icon and file details, and the installer stub, and has imported DLLs load only from System32 (/DEPENDENTLOADFLAG:0x800). A release build with no stub fails. It also embeds the client, from WINAPPMIGRATOR_CLIENT or where scripts/build-client.ps1 builds it, and a release build with no client fails too.

winappmigrator-installer (the stub)

File What it does
src/main.rs Hardens the process, then runs the uninstaller, the headless installer, or the window, by the command line.
src/lib.rs The installer's modules, in a library so their tests run without elevation.
src/gui.rs The installer's window: checks the package, shows what it will set up, previews, installs, and shows the result.
src/headless.rs The command-line installer: its flags, what it prints, and its exit code.
src/uninstall.rs The uninstaller's command line, and --quiet.
src/uninstall_gui.rs The uninstaller's small window.
src/cleanup.rs Chooses a private place to unpack a package, and removes what earlier runs left.
build.rs Embeds the elevation manifest, the icon and file details, with no publisher, and has imported DLLs load only from System32 (/DEPENDENTLOADFLAG:0x800).
tests/installer_e2e.rs Builds an installer with the real stub and runs it. Installs for real only on a GitHub-hosted runner. Elsewhere it previews from an elevated shell, and from a normal one skips running the installer.
tests/elevated_round_trip.rs Sets up a harmless fake app, builds, removes, installs, and takes it back out every way, on a throwaway CI machine only.
tests/elevated_offline_and_profiles.rs The same from a hostile NTFS VHD made to look like another PC's, with real second accounts and every real scheduled task.
tests/elevated_packaging.rs What a build and an install really read and leave, two-file installers with a signature, and refusals for room and platform.
tests/elevated_footprint.rs What a person leaves out and adds, and what must never be offered.
tests/elevated_big_package.rs A real package past 4 GiB, built, installed, and checked.
tests/elevated_move.rs Builds installers of a fake app for other CI machines to install.
tests/elevated_real_apps.rs Builds installers of real open-source apps for other CI machines to install. Also builds them with User Data on, kept on that runner, and builds Mosquitto with its runtime for the job that installs on a PC without one.

The elevated_* tests do nothing unless GITHUB_ACTIONS=true, RUNNER_ENVIRONMENT=github-hosted, and WAM_ELEVATED_E2E=1 are all set. elevated_move.rs also needs WAM_MOVE_OUTPUT, and elevated_real_apps.rs one of the WAM_REAL_APPS_* variables. The end-to-end test needs only the first two, and with them, from an elevated shell, installs for real. Never set any of these on a real PC. See Building and testing.

winappmigrator-ui

File What it does
src/lib.rs window_options, which every window opens with, so nothing about drawing comes from the environment, except WGPU_BACKEND, which can only turn Direct3D 12 off. The Direct3D 12 message.
src/theme.rs The design system: light and dark palettes, spacing, fonts, and a test that every text color meets WCAG AA contrast.
src/widgets.rs Shared, theme-aware building blocks, such as cards, buttons, choice rows, notices, path fields, and progress bars.
src/window.rs How every window opens: fitting the screen, and in the mode chosen in the app or else Windows' own.
src/hardening.rs Restricts where DLLs load from, first thing in both executables. The one place unsafe is allowed.
assets/ The window and file icon.

winappmigrator-link

The encrypted link between the app (the builder) and its client. It builds for Windows 7 as well as 10 and 11, so it uses nothing newer than both have.

File What it does
src/lib.rs The ports, TCP 47732 for the link and UDP 47731 for finding clients, the six-digit code length, and the link's errors.
src/discovery.rs How the builder finds clients: a query to each network's broadcast address, answered by each client with its PC's name, Windows, and architecture. Nothing here is secret or trusted: it only says where to connect.
src/channel.rs Pairing by the code with SPAKE2, so the code never crosses the network, then one key each way from HKDF-SHA256, and each message sealed with ChaCha20-Poly1305 with a count as its nonce, so a message changed, replayed, reordered, or sent back is refused. SPAKE2's randomness is Drawn: 64 bytes taken from Windows before SPAKE2 starts, so that Windows giving none is an error rather than a panic, and wiped once used. They come through getrandom 0.3, which on Windows 7 asks RtlGenRandom in advapi32.dll, a DLL Windows only ever loads from System32. SPAKE2's own would come through getrandom 0.2, which imports bcrypt.dll, and Windows 7, which ignores /DEPENDENTLOADFLAG, would load a bcrypt.dll put beside the client.
src/protocol.rs What the builder asks and the client answers: describe a path, list a folder, or read up to 1 MiB of a file. Each message is a JSON header, then for a read, the bytes.
src/paths.rs Which paths may be asked about at all: below the snapshot's root, in ordinary names, and nothing else. The client checks every path, and the builder checks before it asks.

winappmigrator-client

WinAppMigrator Client, which the app carries and saves for the PC an app is moving off. One 32-bit program for Windows 7 and later, built by scripts/build-client.ps1, and signed in a release, as the app is.

File What it does
src/main.rs Unless it is already the copy in a folder only an administrator can change, runs as that copy, in the same window, and waits for it (run_from_safe_folder). Then takes the snapshot, opens the firewall, shows the code, answers discovery, and pairs and serves one builder at a time. Makes a new code after five wrong ones, lets nothing pair after 20 in a run, gives pairing 15 seconds, ends a link that asks nothing for 30 minutes, and undoes everything when Enter is pressed. Started with --caretaker, it is instead the caretaker each run starts, with no window, which undoes what the run's record still names once the run has ended, however it ended, so closing the window leaves nothing behind.
src/lib.rs The client's modules, in a library so their tests run without elevation, and its version.
src/serve.rs Answering a paired builder: describe, list, and read paths below the snapshot's root, never following a link.
src/system.rs What the client does to the PC, and undoes: a shadow copy of the Windows drive, through WMI and PowerShell 2.0, and two Windows Firewall rules, through netsh. Each is noted in running.txt in the same Program Files folder the client runs from, held open while it runs, so that the run's caretaker (start_caretaker, take_care), or failing that the next run, can undo what a run that was closed or killed left, and a run still going is left alone. safe_folder is WinAppMigrator Client in Program Files, which only an administrator can change, so that no DLL planted beside the client is loaded into it: runs_from_safe_folder says whether this is a copy there, and run_from_safe_folder copies the client there as WinAppMigrator Client <number>.exe, runs it, and removes it afterward. The caretaker removes it after a closed window or a kill, and the next run removes any left. windows_tool starts a tool from System32, and give_windows_environment gives it, and PowerShell, an environment of Windows' own rather than the person's, with System32 as the folder it starts in.
build.rs Embeds a manifest that asks for elevation every time, and has imported DLLs load only from System32 (/DEPENDENTLOADFLAG:0x800), which Windows 7 ignores.

.github/scripts

File What it does
check-stub-embedded.ps1 Checks the app carries the stub, byte for byte, and with -Name client, the client.
check-moved-app.ps1 Installs a fake app's installers on a fresh machine and looks with Windows' own tools.
install-real-apps.ps1 Installs the real apps from their publishers, at exact versions and hashes.
real-apps.json The real apps, their versions, hashes, and licenses.
real-app-checks.ps1 What each real app has to do for a move to count. Each check asks Windows to use the thing.
check-moved-real-apps.ps1 On a fresh machine: shows every check fails, installs, shows they pass, uninstalls, and compares.
check-account-settings.ps1 With User Data on, shows an account's values arrive and go.
check-runtime-arrives.ps1 Takes the Visual C++ runtime off a machine, and shows the installer brings it back.
check-real-windows.ps1 Opens the real windows, takes pictures, and checks they fit and that planted code does not run.
planted-d3d12core.rs A harmless stand-in for a planted Direct3D DLL, which only says it ran.
run-program.ps1 Runs a program, waits for it with a time limit, and says what it said.

Last changed 2026-11-11. Describes WinAppMigrator as of its latest release, 0.6.0.