Skip to content

Fix user mode fonts to install & add repair support - #6619

Draft
David Bennett (dkbennett) wants to merge 3 commits into
microsoft:masterfrom
dkbennett:user/dkbennett/userfonts
Draft

David Bennett (dkbennett) wants to merge 3 commits into
microsoft:masterfrom
dkbennett:user/dkbennett/userfonts

Conversation

@dkbennett

@dkbennett David Bennett (dkbennett) commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

📖 Description

Align user-scope font installation with the machine-scope model to address fonts missing from Windows discovery after sign-out or restart.

  • Install user fonts directly into %LOCALAPPDATA%\Microsoft\Windows\Fonts and register their absolute paths under HKCU\Software\Microsoft\Windows NT\CurrentVersion\Fonts.
  • Track original filenames separately from collision-renamed installed files using the same package inventory mapping strategy for both scopes.
  • Add font repair using installed package metadata. Repair migrates existing nested user installations to the flat layout and restores discovery registrations without downloading fonts.
  • Update validation, inventory, and uninstall to handle both layouts. Remove only mapped files and matching registrations, preserving unrelated files and the shared Fonts directory.

Machine-scope discovery registrations retain their relative filename values. Migration rollback is per-file and best effort.

🔗 References

Addresses #6535.

🔍 Validation

Automated coverage checks exact inventory filenames, flat installation paths, REG_SZ discovery values, scope isolation, filename collisions, repair migration, failure handling, and uninstall cleanup.

AppInstallerCLITests.exe '[fonts],[FontHelper],[RepairFlow]'
Passed: 334 assertions in 29 test cases.
wingetdev font list --details --disable-interactivity: passed against the locally deployed dev build with fonts enabled.

✅ Checklist

🤖 AI Assistance

  • AI assistance was used and has been disclosed in this PR
  • No AI assistance was used

📋 Issue Type

  • Bug fix
  • Feature
  • Task
Microsoft Reviewers: Open in CodeFlow

@github-actions

This comment has been minimized.

Preserve font and pre-indexed source test hooks.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a9e21d38-9ab1-4358-963d-9aadad897ad0
@github-actions

This comment has been minimized.

Add a regression for volatile shared test keys and acknowledge fontlayout in the spelling dictionary.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a9e21d38-9ab1-4358-963d-9aadad897ad0
fontContext.PackageId = ConvertToUTF16(installedPackage->GetProperty(Repository::PackageVersionProperty::Moniker));
fontContext.PackageVersion = ConvertToUTF16(installedPackage->GetProperty(Repository::PackageVersionProperty::Version));

if (fontContext.Scope == Manifest::ScopeEnum::User && Runtime::IsRunningWithNonDefaultFullToken())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whichever merges second will need to update this: #6634

Depending on the specifics, it might already be covered by the general repair flow blocker but I don't remember right now.

context.Add<Execution::Data::RepairString>(repairCommand);
}

bool IsInstallerMappingRequired(Execution::Context& context)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm always the one saying we should have these semantic functions and then this one is not named well enough to indicate the semantic intention.

Can the comment at the call site be moved here?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved font-path collisions and overly restrictive filename validation can block valid installs, repairs, and uninstalls, while malformed inventory mappings can truncate font listings.

3 open issues
What changed in this PR

This PR addresses user fonts disappearing after sign-out or restart by aligning their installation layout with machine-scope fonts. It also adds repair support using installed metadata, without downloading fonts.

Changes:

  • Install user fonts directly in the shared Fonts directory with absolute-path discovery registrations.
  • Add repair to migrate legacy nested installations and restore registrations.
  • Update inventory, validation, uninstall, and tests for both layouts and filename collisions.
File Description
src/​AppInstallerCommonCore/​Public/​winget/​Fonts.h Declares the font repair API.
src/​AppInstallerCommonCore/​Fonts.cpp Implements flat installation, repair migration, mapping validation, and cleanup.
src/​AppInstallerCLITests/​TestHooks.h Adds registry and session-isolation test hooks.
src/​AppInstallerCLITests/​RepairFlow.cpp Tests font repair dispatch and elevation restrictions.
src/​AppInstallerCLITests/​Fonts.cpp Covers layouts, collisions, migration, failures, and uninstall.
src/​AppInstallerCLIE2ETests/​Helpers/​TestCommon.cs Verifies exact inventory filenames and discovery registrations.
src/​AppInstallerCLIE2ETests/​FontCommand.cs Updates installation checks and adds user-font repair coverage.
src/​AppInstallerCLICore/​Workflows/​RepairFlow.cpp Routes font packages through the repair workflow.
src/​AppInstallerCLICore/​Workflows/​FontFlow.h Declares the font repair workflow.
src/​AppInstallerCLICore/​Workflows/​FontFlow.cpp Repairs fonts from installed metadata with scope checks.
.github/​actions/​spelling/​expect.txt Adds the font-layout test tag to spelling expectations.

Review effort: Balanced

const bool inPackage = context.Scope == Manifest::ScopeEnum::User &&
FontPathsEqual(path.parent_path(), GetUserFontPackagePath(context));
THROW_HR_IF_MSG(APPINSTALLER_CLI_ERROR_FONT_VALIDATION_FAILED,
!path.is_absolute() || !Manifest::IsValueSafeForPathConstruction(path.filename().u8string()) || (!inRoot && !inPackage),
Comment on lines 770 to 771
for (const auto& fontFileInfo : validationResult.FontFileInfos)
{
context.PackageId = packageId;
context.PackageVersion = version;
auto fontFile = CreateFontFileInfo(context, filePath, ConvertToUTF16(versionValue.Name()));
auto fontFile = CreateFontFileInfo(context, filePath);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants