Skip to content

CmdPal: Hide uninstall option for system apps#48104

Draft
michaeljolley wants to merge 13 commits into
mainfrom
dev/mjolley/fix-uninstall-system-apps
Draft

CmdPal: Hide uninstall option for system apps#48104
michaeljolley wants to merge 13 commits into
mainfrom
dev/mjolley/fix-uninstall-system-apps

Conversation

@michaeljolley

@michaeljolley michaeljolley commented May 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #46826

The CmdPal "Uninstall" context menu command was shown for system/framework apps that cannot or should not be uninstalled (Control Panel, Task Manager, Registry Editor, Settings, etc.).

Root Cause

Two separate code paths add the Uninstall command:

  1. UWP/MSIX appsUWPApplication.GetCommands() had no guard
  2. Win32/.lnk appsWin32Program.GetCommands() had no guard

Fix

UWP Path

Added IsNonRemovable property to IPackagePackageWrapperUWP, derived from Package.SignatureKind == PackageSignatureKind.System. The uninstall command is gated behind !Package.IsNonRemovable.

Win32/.lnk Path

Added IsProtectedSystemApp() which checks whether the resolved executable path lives under:

  • %SystemRoot%\System32 — core OS binaries
  • %SystemRoot%\SysWOW64 — 32-bit system binaries
  • %SystemRoot%\SystemApps — inbox Windows Store apps

Path-based detection was chosen over registry SystemComponent lookups because:

  1. No additional I/O required (FullPath already resolved during discovery)
  2. System executables reliably live in well-known OS directories
  3. Registry matching for .lnk shortcuts is non-trivial (no product codes)

%ProgramFiles%\WindowsApps is intentionally NOT blocked — Win11 optional features (Notepad, Paint) live there and have valid uninstallers.

Changes

  • IPackage.cs: Added bool IsNonRemovable property
  • PackageWrapper.cs: Implements IsNonRemovable from SignatureKind == System
  • UWP.cs: Threads IsNonRemovable through
  • UWPApplication.cs: Gates uninstall behind !Package.IsNonRemovable
  • Win32Program.cs: Added IsProtectedSystemApp() and gates uninstall behind it

System-signed UWP packages (Settings, Task Manager, Registry Editor)
should not show an uninstall option in the context menu. Add
IsNonRemovable property threaded from Windows.ApplicationModel.Package
.SignatureKind through PackageWrapper -> IPackage -> UWP, and gate the
UninstallApplicationConfirmation behind !Package.IsNonRemovable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@michaeljolley michaeljolley added the Product-Command Palette Refers to the Command Palette utility label May 25, 2026
@michaeljolley michaeljolley self-assigned this May 25, 2026
michaeljolley and others added 2 commits May 24, 2026 23:13
…#46826)

The previous commit guarded UWP system packages via Package.IsNonRemovable.
This commit extends protection to Win32/.lnk-based system utilities (Control
Panel, Task Manager, Registry Editor, etc.) by checking whether the resolved
executable path lives under System32, SysWOW64, or SystemApps.

Path-based detection was chosen over registry SystemComponent lookups because
the FullPath is already resolved during program discovery (no additional I/O),
and system executables reliably reside in these well-known OS directories.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

root and others added 8 commits May 24, 2026 23:34
FullPath for .lnk shortcuts can still point to the shortcut file itself
(e.g., C:\ProgramData\...\Task Manager.lnk) rather than the resolved
target executable. GetAppIdentifier() reliably encodes the actual
executable path after the pipe delimiter (Name|ExePath).

Extract the resolved path via GetResolvedExecutablePath() before running
the system directory check. This ensures Task Manager, Control Panel,
and other System32 targets are correctly identified as protected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The check-spelling bot flagged lowercase 'uninstaller' as unrecognized.
The expect list had 'Uninstaller' (capitalized) but our code comments use
the lowercase form. Added both lowercase variants.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
FullPath for .lnk shortcuts can still point to the shortcut file itself
(e.g., C:\ProgramData\...\Task Manager.lnk) rather than the resolved
target executable. GetAppIdentifier() reliably encodes the actual
executable path after the pipe delimiter (Name|ExePath).

Extract the resolved path via GetResolvedExecutablePath() before running
the system directory check. This ensures Task Manager, Control Panel,
and other System32 targets are correctly identified as protected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@michaeljolley michaeljolley marked this pull request as ready for review May 25, 2026 04:45
@michaeljolley michaeljolley requested a review from zadjii-msft May 25, 2026 04:45
LegendaryBlair added a commit that referenced this pull request May 25, 2026
## Problem

Since #47119 (`Refresh check-spelling 0.0.26`, merged 2026-04-23)
refreshed the check-spelling tooling and rewrote
`.github/actions/spell-check/expect.txt` (938 lines / 633 deletions),
the check-spelling bot has been leaving a noisy advisory comment on
**every PR**:

> #### These words are not needed and should be removed
> ABlocked AClient AColumn ACR ADate ADifferent AHybrid ALarger
AModifier ANull AOklab APeriod ARandom ARemapped ASingle ASUS bck …

The same ~150-word list is appended verbatim to every PR the bot looks
at (verified against #48058, #48102, #48104 — the list is identical).
These tokens are residual orphans in `expect.txt` from before the 0.0.26
refresh and no longer match anything in source.

## Fix

Removes exactly the 147 orphan tokens that the bot has consistently
flagged as `now absent` from `.github/actions/spell-check/expect.txt`.
The removed tokens are exclusively the ones the bot itself identified.

All uppercase Win32 / DirectWrite identifiers that are still used in
source (`DWRITE`, `LWIN`, `VCENTER`, `VREDRAW`, etc.) are **preserved**.

## Verification

- Diff is a single file, deletions only: `expect.txt` shrinks from 2343
→ 2196 lines.
- Each of the 4 uppercase Win32 tokens (`DWRITE` line 514, `LWIN` 1074,
`VCENTER` 2105, `VREDRAW` 2144 in the original) remains in the file.
- The check-spelling job on this PR should now post a clean report (no
`should be removed` block).

## Background — which PR introduced the drift

| PR | Date | What it changed |
|----|------|-----------------|
| **#47119** | 2026-04-23 | Refreshed check-spelling to 0.0.26; rewrote
`expect.txt` with 938 line-changes (633 deletions, 305 additions). The
duplicated lowercase/uppercase entries and many obsolete tokens
originate here. |

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
@michaeljolley michaeljolley marked this pull request as draft May 25, 2026 16:00
root and others added 2 commits May 25, 2026 11:01
…6826)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ly (#46826)

LnkProgram() already resolves FullPath to the shortcut target executable
before storing the Win32Program record. GetResolvedExecutablePath() was
parsing GetAppIdentifier() (which is 'Name|FullPath') and extracting
FullPath right back out — a circular no-op with incorrect doc comments.

Remove the helper and have IsProtectedSystemApp() read FullPath directly,
with updated comments explaining why FullPath is already resolved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product-Command Palette Refers to the Command Palette utility

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CmdPal shows the uninstall button for system apps that arent supposed to be uninstalled

2 participants