Merge branch 'main' into shawn/CLIFileLockSmith

This commit is contained in:
Shawn Yuan (from Dev Box)
2025-12-05 13:31:43 +08:00
37 changed files with 1504 additions and 184 deletions

View File

@@ -773,6 +773,7 @@ INITGUID
INITTOLOGFONTSTRUCT INITTOLOGFONTSTRUCT
INLINEPREFIX INLINEPREFIX
inlines inlines
Inno
INPC INPC
inproc inproc
INPUTHARDWARE INPUTHARDWARE
@@ -1629,6 +1630,7 @@ SKIPOWNPROCESS
sku sku
SLGP SLGP
sln sln
slnx
SMALLICON SMALLICON
smartphone smartphone
smileys smileys
@@ -1847,6 +1849,7 @@ UNCPRIORITY
UNDNAME UNDNAME
UNICODETEXT UNICODETEXT
unins unins
Uninstaller
uninstalls uninstalls
Uniquifies Uniquifies
unitconverter unitconverter

View File

@@ -192,14 +192,14 @@ jobs:
displayName: Verify XAML formatting displayName: Verify XAML formatting
- pwsh: |- - pwsh: |-
& '.pipelines/verifyNugetPackages.ps1' -solution '$(build.sourcesdirectory)\PowerToys.sln' & '.pipelines/verifyNugetPackages.ps1' -solution '$(build.sourcesdirectory)\PowerToys.slnx'
displayName: Verify Nuget package versions for PowerToys.sln displayName: Verify Nuget package versions for PowerToys.slnx
- pwsh: |- - pwsh: |-
& '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\PowerToys.sln' & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\PowerToys.slnx'
& '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\tools\BugReportTool\BugReportTool.sln' & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\tools\BugReportTool\BugReportTool.sln'
& '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\tools\StylesReportTool\StylesReportTool.sln' & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\tools\StylesReportTool\StylesReportTool.sln'
& '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\installer\PowerToysSetup.sln' & '.pipelines/verifyArm64Configuration.ps1' -solution '$(build.sourcesdirectory)\installer\PowerToysSetup.slnx'
displayName: Verify ARM64 configurations displayName: Verify ARM64 configurations
- ${{ if eq(parameters.enablePackageCaching, true) }}: - ${{ if eq(parameters.enablePackageCaching, true) }}:
@@ -252,7 +252,7 @@ jobs:
${{ else }}: ${{ else }}:
displayName: Build PowerToys main project displayName: Build PowerToys main project
inputs: inputs:
solution: 'PowerToys.sln' solution: 'PowerToys.slnx'
vsVersion: 17.0 vsVersion: 17.0
msbuildArgs: >- msbuildArgs: >-
-restore -graph -restore -graph
@@ -275,7 +275,7 @@ jobs:
displayName: Generate DSC artifacts for ARM64 displayName: Generate DSC artifacts for ARM64
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64')) condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
inputs: inputs:
solution: PowerToys.sln solution: PowerToys.slnx
vsVersion: 17.0 vsVersion: 17.0
msbuildArgs: >- msbuildArgs: >-
-restore -restore

View File

@@ -74,7 +74,7 @@ jobs:
command: restore command: restore
feedsToUse: config feedsToUse: config
configPath: nuget.config configPath: nuget.config
restoreSolution: PowerToys.sln restoreSolution: PowerToys.slnx
restoreDirectory: '$(Build.SourcesDirectory)\packages' restoreDirectory: '$(Build.SourcesDirectory)\packages'
# Build all UI test projects if no specific modules are specified # Build all UI test projects if no specific modules are specified

View File

@@ -35,7 +35,7 @@ steps:
- task: VSBuild@1 - task: VSBuild@1
displayName: Build Shared Support DLLs displayName: Build Shared Support DLLs
inputs: inputs:
solution: "**/installer/PowerToysSetup.sln" solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0 vsVersion: 17.0
msbuildArgs: >- msbuildArgs: >-
/t:PowerToysSetupCustomActionsVNext;SilentFilesInUseBAFunction /t:PowerToysSetupCustomActionsVNext;SilentFilesInUseBAFunction
@@ -74,7 +74,7 @@ steps:
- task: VSBuild@1 - task: VSBuild@1
displayName: 💻 Build VNext MSI displayName: 💻 Build VNext MSI
inputs: inputs:
solution: "**/installer/PowerToysSetup.sln" solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0 vsVersion: 17.0
msbuildArgs: >- msbuildArgs: >-
-restore -restore
@@ -91,7 +91,7 @@ steps:
- task: VSBuild@1 - task: VSBuild@1
displayName: 👤 Build VNext MSI displayName: 👤 Build VNext MSI
inputs: inputs:
solution: "**/installer/PowerToysSetup.sln" solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0 vsVersion: 17.0
msbuildArgs: >- msbuildArgs: >-
/t:PowerToysInstallerVNext /t:PowerToysInstallerVNext
@@ -142,7 +142,7 @@ steps:
- task: VSBuild@1 - task: VSBuild@1
displayName: 💻 Build VNext Bootstrapper displayName: 💻 Build VNext Bootstrapper
inputs: inputs:
solution: "**/installer/PowerToysSetup.sln" solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0 vsVersion: 17.0
msbuildArgs: >- msbuildArgs: >-
-restore -restore
@@ -159,7 +159,7 @@ steps:
- task: VSBuild@1 - task: VSBuild@1
displayName: 👤 Build VNext Bootstrapper displayName: 👤 Build VNext Bootstrapper
inputs: inputs:
solution: "**/installer/PowerToysSetup.sln" solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0 vsVersion: 17.0
msbuildArgs: >- msbuildArgs: >-
/t:PowerToysBootstrapperVNext /t:PowerToysBootstrapperVNext

View File

@@ -55,3 +55,12 @@ steps:
nugetConfigPath: '$(build.sourcesdirectory)\nuget.config' nugetConfigPath: '$(build.sourcesdirectory)\nuget.config'
restoreSolution: '$(build.sourcesdirectory)\**\*.sln' restoreSolution: '$(build.sourcesdirectory)\**\*.sln'
includeNuGetOrg: false includeNuGetOrg: false
- task: NuGetCommand@2
displayName: 'Restore NuGet packages (slnx)'
inputs:
command: 'restore'
feedsToUse: 'config'
nugetConfigPath: '$(build.sourcesdirectory)\nuget.config'
restoreSolution: '$(build.sourcesdirectory)\**\*.slnx'
includeNuGetOrg: false

1041
PowerToys.slnx Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -134,7 +134,7 @@ If you prefer, you can alternatively build prerequisite projects for the install
#### Locally compiling the installer #### Locally compiling the installer
1. Open `installer\PowerToysSetup.sln` 1. Open `installer\PowerToysSetup.slnx`
1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` 1. In Visual Studio, in the `Solutions Configuration` drop-down menu select `Release`
1. From the `Build` menu choose `Build Solution`. 1. From the `Build` menu choose `Build Solution`.
@@ -144,9 +144,9 @@ To build the installer from the command line, run `Developer Command Prompt for
``` ```
git clean -xfd -e *exe -- .\installer\ git clean -xfd -e *exe -- .\installer\
MSBuild -t:restore .\installer\PowerToysSetup.sln -p:RestorePackagesConfig=true /p:Platform="x64" /p:Configuration=Release MSBuild -t:restore .\installer\PowerToysSetup.slnx -p:RestorePackagesConfig=true /p:Platform="x64" /p:Configuration=Release
MSBuild -t:Restore -m .\installer\PowerToysSetup.sln /t:PowerToysInstallerVNext /p:Configuration=Release /p:Platform="x64" MSBuild -t:Restore -m .\installer\PowerToysSetup.slnx /t:PowerToysInstallerVNext /p:Configuration=Release /p:Platform="x64"
MSBuild -t:Restore -m .\installer\PowerToysSetup.sln /t:PowerToysBootstrapperVNext /p:Configuration=Release /p:Platform="x64" MSBuild -t:Restore -m .\installer\PowerToysSetup.slnx /t:PowerToysBootstrapperVNext /p:Configuration=Release /p:Platform="x64"
``` ```
### Supported arguments for the .EXE Bootstrapper installer ### Supported arguments for the .EXE Bootstrapper installer

View File

@@ -19,7 +19,7 @@ You can build the entire solution from the command line, which is sometimes fast
2. Navigate to the repository root directory 2. Navigate to the repository root directory
3. Run the following command(don't forget to set the correct platform): 3. Run the following command(don't forget to set the correct platform):
```pwsh ```pwsh
msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.sln /tl /p:NuGetInteractive="true" msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.slnx /tl /p:NuGetInteractive="true"
``` ```
4. This process should complete in approximately 13-14 minutes for a full build 4. This process should complete in approximately 13-14 minutes for a full build

View File

@@ -42,10 +42,10 @@ Or reach out to "tools\build\BUILD-GUIDELINES.md"
### Sample plain msbuild command ### Sample plain msbuild command
```powershell ```powershell
# Restore: # Restore:
msbuild powertoys.sln -t:restore -p:configuration=debug -p:platform=x64 -m msbuild powertoys.slnx -t:restore -p:configuration=debug -p:platform=x64 -m
# Build powertoys sln # Build powertoys slnx
msbuild powertoys.sln -p:configuration=debug -p:platform=x64 -m msbuild powertoys.slnx -p:configuration=debug -p:platform=x64 -m
# dotnet project # dotnet project
msbuild src\settings-ui\Settings.UI\PowerToys.Settings.csproj -p:Platform=x64 -p:Configuration=Debug -m msbuild src\settings-ui\Settings.UI\PowerToys.Settings.csproj -p:Platform=x64 -p:Configuration=Debug -m
@@ -122,7 +122,7 @@ Similar for attach to managed code.
| Task | Command / Action | Notes | | Task | Command / Action | Notes |
|------|------------------|-------| |------|------------------|-------|
| Clean | `git clean -xdf` (careful) or `msbuild /t:Clean PowerToys.sln` | Deep clean removes packages & build outputs | | Clean | `git clean -xdf` (careful) or `msbuild /t:Clean PowerToys.slnx` | Deep clean removes packages & build outputs |
| Rebuild single project | `msbuild path\to\proj.vcxproj /t:Rebuild -p:Platform=x64 -p:Configuration=Debug` | Faster than whole solution | | Rebuild single project | `msbuild path\to\proj.vcxproj /t:Rebuild -p:Platform=x64 -p:Configuration=Debug` | Faster than whole solution |
| Generate installer (rare in inner loop) | See `tools\build\build-installer.ps1` | Usually not needed for local debug | | Generate installer (rare in inner loop) | See `tools\build\build-installer.ps1` | Usually not needed for local debug |
| Resource conversion errors | Re-run restore + build | Triggers custom PowerShell targets | | Resource conversion errors | Re-run restore + build | Triggers custom PowerShell targets |

View File

@@ -12,7 +12,7 @@
- Exit PowerToys if it's running. - Exit PowerToys if it's running.
- Open `PowerToys.sln` in Visual Studio and build the solution. - Open `PowerToys.slnx` in Visual Studio and build the solution.
- Run tests in the Test Explorer (`Test > Test Explorer` or `Ctrl+E, T`). - Run tests in the Test Explorer (`Test > Test Explorer` or `Ctrl+E, T`).

View File

@@ -86,7 +86,7 @@ The module provides a user interface for configuring settings in the PowerToys S
### Building and Testing ### Building and Testing
1. Clone the repository: `git clone https://github.com/microsoft/PowerToys.git` 1. Clone the repository: `git clone https://github.com/microsoft/PowerToys.git`
2. Open PowerToys.sln in Visual Studio 2. Open PowerToys.slnx in Visual Studio
3. Select the Release configuration and build the solution 3. Select the Release configuration and build the solution
4. Run PowerToys.exe from the output directory to test the module 4. Run PowerToys.exe from the output directory to test the module

View File

@@ -161,7 +161,7 @@ FancyZones is divided into several projects:
``` ```
git clone https://github.com/microsoft/PowerToys.git git clone https://github.com/microsoft/PowerToys.git
``` ```
2. Open `PowerToys.sln` in Visual Studio 2. Open `PowerToys.slnx` in Visual Studio
3. Select the Release configuration and build the solution 3. Select the Release configuration and build the solution
4. If you encounter build errors, try deleting the x64 output folder and rebuild 4. If you encounter build errors, try deleting the x64 output folder and rebuild
@@ -244,7 +244,7 @@ UI tests are implemented using [Windows Application Driver](https://github.com/m
- Exit PowerToys if it's running - Exit PowerToys if it's running
- Run WinAppDriver.exe from the installation directory. Skip this step if installed in the default directory (`C:\Program Files (x86)\Windows Application Driver`); in this case, it'll be launched automatically during tests. - Run WinAppDriver.exe from the installation directory. Skip this step if installed in the default directory (`C:\Program Files (x86)\Windows Application Driver`); in this case, it'll be launched automatically during tests.
- Open `PowerToys.sln` in Visual Studio and build the solution. - Open `PowerToys.slnx` in Visual Studio and build the solution.
- Run tests in the Test Explorer (`Test > Test Explorer` or `Ctrl+E, T`). - Run tests in the Test Explorer (`Test > Test Explorer` or `Ctrl+E, T`).
>Note: notifications or other application windows, that are shown above the window under test, can disrupt the testing process. >Note: notifications or other application windows, that are shown above the window under test, can disrupt the testing process.

View File

@@ -11,7 +11,7 @@ Keyboard Manager consists of two main components:
## Development Environment Setup ## Development Environment Setup
1. Clone the PowerToys repository 1. Clone the PowerToys repository
2. Open `PowerToys.sln` in Visual Studio 2. Open `PowerToys.slnx` in Visual Studio
3. Ensure all NuGet packages are restored 3. Ensure all NuGet packages are restored
4. Build the entire solution in Debug configuration 4. Build the entire solution in Debug configuration

View File

@@ -92,7 +92,7 @@ The modules settings are exposed in the PowerToys Settings UI. Options includ
3. Build the solution: 3. Build the solution:
```sh ```sh
msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.sln msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.slnx
``` ```
> Note: This may take some time. > Note: This may take some time.

View File

@@ -53,7 +53,7 @@ The Screen Ruler module consists of several components:
### Building ### Building
1. Open PowerToys.sln in Visual Studio 1. Open PowerToys.slnx in Visual Studio
2. In the Solutions Configuration drop-down menu, select Release or Debug 2. In the Solutions Configuration drop-down menu, select Release or Debug
3. From the Build menu, choose Build Solution 3. From the Build menu, choose Build Solution
4. The executable app for Screen Ruler is named PowerToys.MeasureToolUI.exe 4. The executable app for Screen Ruler is named PowerToys.MeasureToolUI.exe

View File

@@ -19,7 +19,7 @@ Shortcut Guide is a PowerToy that displays an overlay of available keyboard shor
## Build and Debug Instructions ## Build and Debug Instructions
### Build ### Build
1. Open PowerToys.sln in Visual Studio 1. Open PowerToys.slnx in Visual Studio
2. Select Release or Debug in the Solutions Configuration drop-down menu 2. Select Release or Debug in the Solutions Configuration drop-down menu
3. From the Build menu, choose Build Solution 3. From the Build menu, choose Build Solution
4. The executable is named PowerToys.ShortcutGuide.exe 4. The executable is named PowerToys.ShortcutGuide.exe

View File

@@ -80,7 +80,7 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and an
### Install Visual Studio dependencies ### Install Visual Studio dependencies
1. Open the `PowerToys.sln` file. 1. Open the `PowerToys.slnx` file.
1. If you see a dialog that says `install extra components` in the solution explorer pane, click `install` 1. If you see a dialog that says `install extra components` in the solution explorer pane, click `install`
### Get Submodules to compile ### Get Submodules to compile
@@ -93,7 +93,7 @@ We have submodules that need to be initialized before you can compile most parts
### Compiling Source Code ### Compiling Source Code
- Open `PowerToys.sln` in Visual Studio. - Open `PowerToys.slnx` in Visual Studio.
- In the `Solutions Configuration` drop-down menu select `Release` or `Debug`. - In the `Solutions Configuration` drop-down menu select `Release` or `Debug`.
- From the `Build` menu choose `Build Solution`, or press <kbd>Control</kbd>+<kbd>Shift</kbd>+<kbd>b</kbd> on your keyboard. - From the `Build` menu choose `Build Solution`, or press <kbd>Control</kbd>+<kbd>Shift</kbd>+<kbd>b</kbd> on your keyboard.
- The build process may take several minutes depending on your computer's performance. Once it completes, the PowerToys binaries will be in your repo under `x64\Release\`. - The build process may take several minutes depending on your computer's performance. Once it completes, the PowerToys binaries will be in your repo under `x64\Release\`.
@@ -107,10 +107,10 @@ Our installer is two parts, an EXE and an MSI. The EXE (Bootstrapper) contains
The installer can only be compiled in `Release` mode; steps 1 and 2 must be performed before the MSI can be compiled. The installer can only be compiled in `Release` mode; steps 1 and 2 must be performed before the MSI can be compiled.
1. Compile `PowerToys.sln`. Instructions are listed above. 1. Compile `PowerToys.slnx`. Instructions are listed above.
1. Compile `BugReportTool.sln` tool. Path from root: `tools\BugReportTool\BugReportTool.sln` (details listed below) 1. Compile `BugReportTool.sln` tool. Path from root: `tools\BugReportTool\BugReportTool.sln` (details listed below)
1. Compile `StylesReportTool.sln` tool. Path from root: `tools\StylesReportTool\StylesReportTool.sln` (details listed below) 1. Compile `StylesReportTool.sln` tool. Path from root: `tools\StylesReportTool\StylesReportTool.sln` (details listed below)
1. Compile `PowerToysSetup.sln` Path from root: `installer\PowerToysSetup.sln` (details listed below) 1. Compile `PowerToysSetup.slnx` Path from root: `installer\PowerToysSetup.slnx` (details listed below)
See [Installer](core/installer.md) for more details on building and debugging the installer. See [Installer](core/installer.md) for more details on building and debugging the installer.

View File

@@ -1,96 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32414.318
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spdlog", "..\src\logging\logging.vcxproj", "{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logger", "..\src\common\logger\logger.vcxproj", "{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Version", "..\src\common\version\version.vcxproj", "{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EtwTrace", "..\src\common\Telemetry\EtwTrace\EtwTrace.vcxproj", "{8F021B46-362B-485C-BFBA-CCF83E820CBD}"
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "PowerToysInstallerVNext", "PowerToysSetupVNext\PowerToysInstallerVNext.wixproj", "{B6E94700-DF38-41F6-A3FD-18B69674AB1E}"
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "PowerToysBootstrapperVNext", "PowerToysSetupVNext\PowerToysBootstrapperVNext.wixproj", "{DA4E9744-80BE-424C-B0F5-AFD8757DB575}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToysSetupCustomActionsVNext", "PowerToysSetupCustomActionsVNext\PowerToysSetupCustomActionsVNext.vcxproj", "{B3A354B0-1E54-4B55-A962-FB5AF9330C19}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SilentFilesInUseBAFunction", "PowerToysSetupVNext\SilentFilesInUseBA\SilentFilesInUseBAFunction.vcxproj", "{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.Build.0 = Debug|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|ARM64.ActiveCfg = Release|ARM64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|ARM64.Build.0 = Release|ARM64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.ActiveCfg = Release|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.Build.0 = Release|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|ARM64.ActiveCfg = Debug|ARM64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.ActiveCfg = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.Build.0 = Debug|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|ARM64.ActiveCfg = Release|ARM64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|ARM64.Build.0 = Release|ARM64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.ActiveCfg = Release|x64
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.Build.0 = Release|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|ARM64.ActiveCfg = Debug|ARM64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|ARM64.Build.0 = Debug|ARM64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.ActiveCfg = Debug|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.Build.0 = Debug|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|ARM64.ActiveCfg = Release|ARM64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|ARM64.Build.0 = Release|ARM64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.ActiveCfg = Release|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.Build.0 = Release|x64
{8F021B46-362B-485C-BFBA-CCF83E820CBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8F021B46-362B-485C-BFBA-CCF83E820CBD}.Debug|ARM64.Build.0 = Debug|ARM64
{8F021B46-362B-485C-BFBA-CCF83E820CBD}.Debug|x64.ActiveCfg = Debug|x64
{8F021B46-362B-485C-BFBA-CCF83E820CBD}.Debug|x64.Build.0 = Debug|x64
{8F021B46-362B-485C-BFBA-CCF83E820CBD}.Release|ARM64.ActiveCfg = Release|ARM64
{8F021B46-362B-485C-BFBA-CCF83E820CBD}.Release|ARM64.Build.0 = Release|ARM64
{8F021B46-362B-485C-BFBA-CCF83E820CBD}.Release|x64.ActiveCfg = Release|x64
{8F021B46-362B-485C-BFBA-CCF83E820CBD}.Release|x64.Build.0 = Release|x64
{B6E94700-DF38-41F6-A3FD-18B69674AB1E}.Debug|ARM64.ActiveCfg = Debug|ARM64
{B6E94700-DF38-41F6-A3FD-18B69674AB1E}.Debug|ARM64.Build.0 = Debug|ARM64
{B6E94700-DF38-41F6-A3FD-18B69674AB1E}.Debug|x64.ActiveCfg = Debug|x64
{B6E94700-DF38-41F6-A3FD-18B69674AB1E}.Debug|x64.Build.0 = Debug|x64
{B6E94700-DF38-41F6-A3FD-18B69674AB1E}.Release|ARM64.ActiveCfg = Release|ARM64
{B6E94700-DF38-41F6-A3FD-18B69674AB1E}.Release|ARM64.Build.0 = Release|ARM64
{B6E94700-DF38-41F6-A3FD-18B69674AB1E}.Release|x64.ActiveCfg = Release|x64
{B6E94700-DF38-41F6-A3FD-18B69674AB1E}.Release|x64.Build.0 = Release|x64
{DA4E9744-80BE-424C-B0F5-AFD8757DB575}.Debug|ARM64.ActiveCfg = Debug|ARM64
{DA4E9744-80BE-424C-B0F5-AFD8757DB575}.Debug|ARM64.Build.0 = Debug|ARM64
{DA4E9744-80BE-424C-B0F5-AFD8757DB575}.Debug|x64.ActiveCfg = Debug|x64
{DA4E9744-80BE-424C-B0F5-AFD8757DB575}.Debug|x64.Build.0 = Debug|x64
{DA4E9744-80BE-424C-B0F5-AFD8757DB575}.Release|ARM64.ActiveCfg = Release|ARM64
{DA4E9744-80BE-424C-B0F5-AFD8757DB575}.Release|ARM64.Build.0 = Release|ARM64
{DA4E9744-80BE-424C-B0F5-AFD8757DB575}.Release|x64.ActiveCfg = Release|x64
{DA4E9744-80BE-424C-B0F5-AFD8757DB575}.Release|x64.Build.0 = Release|x64
{B3A354B0-1E54-4B55-A962-FB5AF9330C19}.Debug|ARM64.ActiveCfg = Debug|ARM64
{B3A354B0-1E54-4B55-A962-FB5AF9330C19}.Debug|x64.ActiveCfg = Debug|x64
{B3A354B0-1E54-4B55-A962-FB5AF9330C19}.Debug|x64.Build.0 = Debug|x64
{B3A354B0-1E54-4B55-A962-FB5AF9330C19}.Release|ARM64.ActiveCfg = Release|ARM64
{B3A354B0-1E54-4B55-A962-FB5AF9330C19}.Release|ARM64.Build.0 = Release|ARM64
{B3A354B0-1E54-4B55-A962-FB5AF9330C19}.Release|x64.ActiveCfg = Release|x64
{B3A354B0-1E54-4B55-A962-FB5AF9330C19}.Release|x64.Build.0 = Release|x64
{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}.Debug|x64.ActiveCfg = Debug|x64
{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}.Debug|x64.Build.0 = Debug|x64
{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}.Release|ARM64.ActiveCfg = Release|ARM64
{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}.Release|ARM64.Build.0 = Release|ARM64
{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}.Release|x64.ActiveCfg = Release|x64
{F8B9F842-F5C3-4A2D-8C85-7F8B9E2B4F1D}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B7A3DA30-D443-40FF-AC51-988AD41E3962}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,22 @@
<Solution>
<Configurations>
<Platform Name="ARM64" />
<Platform Name="x64" />
</Configurations>
<Project Path="../src/common/logger/logger.vcxproj" Id="d9b8fc84-322a-4f9f-bbb9-20915c47ddfd">
<Build Solution="Debug|ARM64" Project="false" />
</Project>
<Project Path="../src/common/Telemetry/EtwTrace/EtwTrace.vcxproj" Id="8f021b46-362b-485c-bfba-ccf83e820cbd" />
<Project Path="../src/common/version/version.vcxproj" Id="cc6e41ac-8174-4e8a-8d22-85dd7f4851df" />
<Project Path="../src/logging/logging.vcxproj" Id="7e1e3f13-2bd6-3f75-a6a7-873a2b55c60f">
<Build Solution="Debug|ARM64" Project="false" />
</Project>
<Project Path="PowerToysSetupCustomActionsVNext/PowerToysSetupCustomActionsVNext.vcxproj" Id="b3a354b0-1e54-4b55-a962-fb5af9330c19">
<Build Solution="Debug|ARM64" Project="false" />
</Project>
<Project Path="PowerToysSetupVNext/PowerToysBootstrapperVNext.wixproj" Type="b7dd6f7e-def8-4e67-b5b7-07ef123db6f0" />
<Project Path="PowerToysSetupVNext/PowerToysInstallerVNext.wixproj" Type="b7dd6f7e-def8-4e67-b5b7-07ef123db6f0" />
<Project Path="PowerToysSetupVNext/SilentFilesInUseBA/SilentFilesInUseBAFunction.vcxproj" Id="f8b9f842-f5c3-4a2d-8c85-7f8b9e2b4f1d">
<Build Solution="Debug|ARM64" Project="false" />
</Project>
</Solution>

View File

@@ -135,8 +135,9 @@ public partial class App : Application
try try
{ {
var winget = new WinGetExtensionCommandsProvider(); var winget = new WinGetExtensionCommandsProvider();
var callback = allApps.LookupApp; winget.SetAllLookup(
winget.SetAllLookup(callback); query => allApps.LookupAppByPackageFamilyName(query, requireSingleMatch: true),
query => allApps.LookupAppByProductCode(query, requireSingleMatch: true));
services.AddSingleton<ICommandProvider>(winget); services.AddSingleton<ICommandProvider>(winget);
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -58,7 +58,7 @@ public class AllAppsCommandProviderTests : AppsTestBase
var provider = new AllAppsCommandProvider(page); var provider = new AllAppsCommandProvider(page);
// Act // Act
var result = provider.LookupApp(string.Empty); var result = provider.LookupAppByDisplayName(string.Empty);
// Assert // Assert
Assert.IsNotNull(result); Assert.IsNotNull(result);
@@ -77,7 +77,7 @@ public class AllAppsCommandProviderTests : AppsTestBase
await WaitForPageInitializationAsync(); await WaitForPageInitializationAsync();
// Act // Act
var result = provider.LookupApp("TestApp"); var result = provider.LookupAppByDisplayName("TestApp");
// Assert // Assert
Assert.IsNotNull(result); Assert.IsNotNull(result);
@@ -97,7 +97,7 @@ public class AllAppsCommandProviderTests : AppsTestBase
await WaitForPageInitializationAsync(); await WaitForPageInitializationAsync();
// Act // Act
var result = provider.LookupApp("NonExistentApp"); var result = provider.LookupAppByDisplayName("NonExistentApp");
// Assert // Assert
Assert.IsNull(result); Assert.IsNull(result);

View File

@@ -4,6 +4,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.CmdPal.Ext.Apps.Helpers;
using Microsoft.CmdPal.Ext.Apps.Programs;
using Microsoft.CmdPal.Ext.Apps.Properties; using Microsoft.CmdPal.Ext.Apps.Properties;
using Microsoft.CmdPal.Ext.Apps.State; using Microsoft.CmdPal.Ext.Apps.State;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
@@ -66,7 +68,71 @@ public partial class AllAppsCommandProvider : CommandProvider
public override ICommandItem[] TopLevelCommands() => [_listItem, .. _page.GetPinnedApps()]; public override ICommandItem[] TopLevelCommands() => [_listItem, .. _page.GetPinnedApps()];
public ICommandItem? LookupApp(string displayName) public ICommandItem? LookupAppByPackageFamilyName(string packageFamilyName, bool requireSingleMatch)
{
if (string.IsNullOrEmpty(packageFamilyName))
{
return null;
}
var items = _page.GetItems();
List<ICommandItem> matches = [];
foreach (var item in items)
{
if (item is AppListItem appItem && string.Equals(packageFamilyName, appItem.App.PackageFamilyName, StringComparison.OrdinalIgnoreCase))
{
matches.Add(item);
if (!requireSingleMatch)
{
// Return early if we don't require uniqueness.
return item;
}
}
}
return requireSingleMatch && matches.Count == 1 ? matches[0] : null;
}
public ICommandItem? LookupAppByProductCode(string productCode, bool requireSingleMatch)
{
if (string.IsNullOrEmpty(productCode))
{
return null;
}
if (!UninstallRegistryAppLocator.TryGetInstallInfo(productCode, out _, out var candidates) || candidates.Count <= 0)
{
return null;
}
var items = _page.GetItems();
List<ICommandItem> matches = [];
foreach (var item in items)
{
if (item is not AppListItem appListItem || string.IsNullOrEmpty(appListItem.App.FullExecutablePath))
{
continue;
}
foreach (var candidate in candidates)
{
if (string.Equals(appListItem.App.FullExecutablePath, candidate, StringComparison.OrdinalIgnoreCase))
{
matches.Add(item);
if (!requireSingleMatch)
{
return item;
}
}
}
}
return requireSingleMatch && matches.Count == 1 ? matches[0] : null;
}
public ICommandItem? LookupAppByDisplayName(string displayName)
{ {
var items = _page.GetItems(); var items = _page.GetItems();

View File

@@ -29,6 +29,10 @@ public sealed class AppItem
public string AppIdentifier { get; set; } = string.Empty; public string AppIdentifier { get; set; } = string.Empty;
public string? PackageFamilyName { get; set; }
public string? FullExecutablePath { get; set; }
public AppItem() public AppItem()
{ {
} }

View File

@@ -40,6 +40,8 @@ public sealed partial class AppListItem : ListItem
public string AppIdentifier => _app.AppIdentifier; public string AppIdentifier => _app.AppIdentifier;
public AppItem App => _app;
public AppListItem(AppItem app, bool useThumbnails, bool isPinned) public AppListItem(AppItem app, bool useThumbnails, bool isPinned)
{ {
Command = _appCommand = new AppCommand(app); Command = _appCommand = new AppCommand(app);
@@ -82,6 +84,12 @@ public sealed partial class AppListItem : ListItem
metadata.Add(new DetailsElement() { Key = "Path", Data = new DetailsLink() { Text = _app.ExePath } }); metadata.Add(new DetailsElement() { Key = "Path", Data = new DetailsLink() { Text = _app.ExePath } });
} }
#if DEBUG
metadata.Add(new DetailsElement() { Key = "[DEBUG] AppIdentifier", Data = new DetailsLink() { Text = _app.AppIdentifier } });
metadata.Add(new DetailsElement() { Key = "[DEBUG] ExePath", Data = new DetailsLink() { Text = _app.ExePath } });
metadata.Add(new DetailsElement() { Key = "[DEBUG] IcoPath", Data = new DetailsLink() { Text = _app.IcoPath } });
#endif
// Icon // Icon
IconInfo? heroImage = null; IconInfo? heroImage = null;
if (_app.IsPackaged) if (_app.IsPackaged)

View File

@@ -0,0 +1,205 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Win32;
namespace Microsoft.CmdPal.Ext.Apps.Helpers;
internal static class UninstallRegistryAppLocator
{
private static readonly string[] UninstallBaseKeys =
[
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
];
/// <summary>
/// Tries to find install directory and a list of plausible main EXEs from an uninstall key
/// (e.g. Inno Setup keys like "{guid}_is1").
/// <paramref name="exeCandidates"/> may be empty if we couldn't pick any safe EXEs.
/// </summary>
/// <returns>
/// Returns true if the uninstall key is found and an install directory is resolved.
/// </returns>
public static bool TryGetInstallInfo(
string uninstallKeyName,
out string? installDir,
out IReadOnlyList<string> exeCandidates,
string? expectedExeName = null)
{
installDir = null;
exeCandidates = [];
if (string.IsNullOrWhiteSpace(uninstallKeyName))
{
throw new ArgumentException("Key name must not be null or empty.", nameof(uninstallKeyName));
}
uninstallKeyName = uninstallKeyName.Trim();
foreach (var baseKeyPath in UninstallBaseKeys)
{
// HKLM
using (var key = Registry.LocalMachine.OpenSubKey($"{baseKeyPath}\\{uninstallKeyName}"))
{
if (TryFromUninstallKey(key, expectedExeName, out installDir, out exeCandidates))
{
return true;
}
}
// HKCU
using (var key = Registry.CurrentUser.OpenSubKey($"{baseKeyPath}\\{uninstallKeyName}"))
{
if (TryFromUninstallKey(key, expectedExeName, out installDir, out exeCandidates))
{
return true;
}
}
}
return false;
}
private static bool TryFromUninstallKey(
RegistryKey? key,
string? expectedExeName,
out string? installDir,
out IReadOnlyList<string> exeCandidates)
{
installDir = null;
exeCandidates = [];
if (key is null)
{
return false;
}
var location = (key.GetValue("InstallLocation") as string)?.Trim('"', ' ', '\t');
if (string.IsNullOrEmpty(location))
{
location = (key.GetValue("Inno Setup: App Path") as string)?.Trim('"', ' ', '\t');
}
if (string.IsNullOrEmpty(location))
{
var uninstall = key.GetValue("UninstallString") as string;
var uninsExe = ExtractFirstPath(uninstall);
if (!string.IsNullOrEmpty(uninsExe))
{
var dir = Path.GetDirectoryName(uninsExe);
if (!string.IsNullOrEmpty(dir) && Directory.Exists(dir))
{
location = dir;
}
}
}
if (string.IsNullOrEmpty(location) || !Directory.Exists(location))
{
return false;
}
installDir = location;
// Collect safe EXE candidates; may be empty if ambiguous or only uninstall exes exist.
exeCandidates = GetExeCandidates(location, expectedExeName);
return true;
}
private static IReadOnlyList<string> GetExeCandidates(string root, string? expectedExeName)
{
// Look at root and a "bin" subfolder (very common pattern)
var allExes = Directory.EnumerateFiles(root, "*.exe", SearchOption.TopDirectoryOnly)
.Concat(GetBinExes(root))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
if (allExes.Length == 0)
{
return [];
}
var result = new List<string>();
// 1) Exact match on expected exe name (if provided), ignoring case, and not uninstall/setup-like.
if (!string.IsNullOrWhiteSpace(expectedExeName))
{
foreach (var exe in allExes)
{
if (string.Equals(Path.GetFileName(exe), expectedExeName, StringComparison.OrdinalIgnoreCase) &&
!LooksLikeUninstallerOrSetup(exe))
{
result.Add(exe);
}
}
}
// 2) All other non-uninstall/setup exes
foreach (var exe in allExes)
{
if (LooksLikeUninstallerOrSetup(exe))
{
continue;
}
// Skip ones already added as expectedExeName matches
if (result.Contains(exe, StringComparer.OrdinalIgnoreCase))
{
continue;
}
result.Add(exe);
}
// 3) We intentionally do NOT add uninstall/setup/update exes here.
// If you ever want them, you can add a separate API to expose them.
return result;
}
private static IEnumerable<string> GetBinExes(string root)
{
var bin = Path.Combine(root, "bin");
return !Directory.Exists(bin)
? []
: Directory.EnumerateFiles(bin, "*.exe", SearchOption.TopDirectoryOnly);
}
private static bool LooksLikeUninstallerOrSetup(string path)
{
var name = Path.GetFileName(path);
return name.StartsWith("unins", StringComparison.OrdinalIgnoreCase) // e.g. Inno: unins000.exe
|| name.Contains("setup", StringComparison.OrdinalIgnoreCase) // setup.exe
|| name.Contains("installer", StringComparison.OrdinalIgnoreCase) // installer.exe / MyAppInstaller.exe
|| name.Contains("update", StringComparison.OrdinalIgnoreCase); // updater/updater.exe
}
private static string? ExtractFirstPath(string? commandLine)
{
if (string.IsNullOrWhiteSpace(commandLine))
{
return null;
}
commandLine = commandLine.Trim();
if (commandLine.StartsWith('"'))
{
var endQuote = commandLine.IndexOf('"', 1);
if (endQuote > 1)
{
return commandLine[1..endQuote];
}
}
var firstSpace = commandLine.IndexOf(' ');
var candidate = firstSpace > 0 ? commandLine[..firstSpace] : commandLine;
candidate = candidate.Trim('"');
return candidate.Length > 0 ? candidate : null;
}
}

View File

@@ -558,6 +558,7 @@ public class UWPApplication : IUWPApplication
IsPackaged = true, IsPackaged = true,
Commands = app.GetCommands(), Commands = app.GetCommands(),
AppIdentifier = app.GetAppIdentifier(), AppIdentifier = app.GetAppIdentifier(),
PackageFamilyName = app.Package.FamilyName,
}; };
return item; return item;
} }

View File

@@ -1065,6 +1065,7 @@ public class Win32Program : IProgram
DirPath = app.Location, DirPath = app.Location,
Commands = app.GetCommands(), Commands = app.GetCommands(),
AppIdentifier = app.GetAppIdentifier(), AppIdentifier = app.GetAppIdentifier(),
FullExecutablePath = app.FullPath,
}; };
} }
} }

View File

@@ -62,7 +62,7 @@ public partial class InstallPackageCommand : InvokableCommand
{ {
PackageInstallCommandState.Install => Icons.DownloadIcon, PackageInstallCommandState.Install => Icons.DownloadIcon,
PackageInstallCommandState.Update => Icons.UpdateIcon, PackageInstallCommandState.Update => Icons.UpdateIcon,
PackageInstallCommandState.Uninstall => Icons.CompletedIcon, PackageInstallCommandState.Uninstall => Icons.DeleteIcon,
_ => throw new NotImplementedException(), _ => throw new NotImplementedException(),
}; };
Name = InstallCommandState switch Name = InstallCommandState switch

View File

@@ -194,46 +194,95 @@ public partial class InstallPackageListItem : ListItem
var isInstalled = _package.InstalledVersion is not null; var isInstalled = _package.InstalledVersion is not null;
var installedState = isInstalled ? var installedState = isInstalled ?
(_package.IsUpdateAvailable ? (_package.IsUpdateAvailable ? PackageInstallCommandState.Update : PackageInstallCommandState.Uninstall) :
PackageInstallCommandState.Update : PackageInstallCommandState.Uninstall) :
PackageInstallCommandState.Install; PackageInstallCommandState.Install;
// might be an uninstall command // might be an uninstall command
InstallPackageCommand installCommand = new(_package, installedState); InstallPackageCommand installCommand = new(_package, installedState);
if (isInstalled) if (_package.InstalledVersion is not null)
{ {
this.Icon = installCommand.Icon; #if DEBUG
this.Command = new NoOpCommand(); var installerType = _package.InstalledVersion.GetMetadata(PackageVersionMetadataField.InstallerType);
Subtitle = installerType + " | " + Subtitle;
#endif
List<IContextItem> contextMenu = []; List<IContextItem> contextMenu = [];
CommandContextItem uninstallContextItem = new(installCommand) Command = installCommand;
Icon = installedState switch
{ {
IsCritical = true, PackageInstallCommandState.Install => Icons.DownloadIcon,
Icon = Icons.DeleteIcon, PackageInstallCommandState.Update => Icons.UpdateIcon,
PackageInstallCommandState.Uninstall => Icons.CompletedIcon,
_ => Icons.DownloadIcon,
}; };
if (WinGetStatics.AppSearchCallback is not null) TryLocateAndAppendActionForApp(contextMenu);
MoreCommands = contextMenu.ToArray();
}
else
{
_installCommand = new InstallPackageCommand(_package, installedState);
_installCommand.InstallStateChanged += InstallStateChangedHandler;
Command = _installCommand;
Icon = _installCommand.Icon;
}
}
private void TryLocateAndAppendActionForApp(List<IContextItem> contextMenu)
{
try
{
// Let's try to connect it to an installed app if possible
// This is a bit of dark magic, since there's no direct link between
// WinGet packages and installed apps.
var lookupByPackageName = WinGetStatics.AppSearchByPackageFamilyNameCallback;
if (lookupByPackageName is not null)
{ {
var callback = WinGetStatics.AppSearchCallback; var names = _package.InstalledVersion.PackageFamilyNames;
var installedApp = callback(_package.DefaultInstallVersion is null ? _package.Name : _package.DefaultInstallVersion.DisplayName); for (var i = 0; i < names.Count; i++)
if (installedApp is not null)
{ {
this.Command = installedApp.Command; var installedAppByPfn = lookupByPackageName(names[i]);
contextMenu = [.. installedApp.MoreCommands]; if (installedAppByPfn is not null)
{
contextMenu.Add(new Separator());
contextMenu.Add(new CommandContextItem(installedAppByPfn.Command));
foreach (var item in installedAppByPfn.MoreCommands)
{
contextMenu.Add(item);
}
return;
}
} }
} }
contextMenu.Add(uninstallContextItem); var lookupByProductCode = WinGetStatics.AppSearchByProductCodeCallback;
this.MoreCommands = contextMenu.ToArray(); if (lookupByProductCode is not null)
return; {
var productCodes = _package.InstalledVersion.ProductCodes;
for (var i = 0; i < productCodes.Count; i++)
{
var installedAppByProductCode = lookupByProductCode(productCodes[i]);
if (installedAppByProductCode is not null)
{
contextMenu.Add(new Separator());
contextMenu.Add(new CommandContextItem(installedAppByProductCode.Command));
foreach (var item in installedAppByProductCode.MoreCommands)
{
contextMenu.Add(item);
}
return;
}
}
}
}
catch (Exception ex)
{
Logger.LogError($"Failed to retrieve app context menu items for package '{_package?.Name ?? "Unknown"}'", ex);
} }
// didn't find the app
_installCommand = new InstallPackageCommand(_package, installedState);
this.Command = _installCommand;
Icon = _installCommand.Icon;
_installCommand.InstallStateChanged += InstallStateChangedHandler;
} }
private void InstallStateChangedHandler(object? sender, InstallPackageCommand e) private void InstallStateChangedHandler(object? sender, InstallPackageCommand e)

View File

@@ -41,5 +41,9 @@ public partial class WinGetExtensionCommandsProvider : CommandProvider
public override void InitializeWithHost(IExtensionHost host) => WinGetExtensionHost.Instance.Initialize(host); public override void InitializeWithHost(IExtensionHost host) => WinGetExtensionHost.Instance.Initialize(host);
public void SetAllLookup(Func<string, ICommandItem?> callback) => WinGetStatics.AppSearchCallback = callback; public void SetAllLookup(Func<string, ICommandItem?> lookupByPackageName, Func<string, ICommandItem?> lookupByProductCode)
{
WinGetStatics.AppSearchByPackageFamilyNameCallback = lookupByPackageName;
WinGetStatics.AppSearchByProductCodeCallback = lookupByProductCode;
}
} }

View File

@@ -34,7 +34,9 @@ internal static class WinGetStatics
private static readonly StatusMessage _errorMessage = new() { State = MessageState.Error }; private static readonly StatusMessage _errorMessage = new() { State = MessageState.Error };
public static Func<string, ICommandItem?>? AppSearchCallback { get; set; } public static Func<string, ICommandItem?>? AppSearchByPackageFamilyNameCallback { get; set; }
public static Func<string, ICommandItem?>? AppSearchByProductCodeCallback { get; set; }
private static readonly CompositeFormat CreateCatalogErrorMessage = System.Text.CompositeFormat.Parse(Properties.Resources.winget_create_catalog_error); private static readonly CompositeFormat CreateCatalogErrorMessage = System.Text.CompositeFormat.Parse(Properties.Resources.winget_create_catalog_error);

View File

@@ -56,7 +56,7 @@ if ($IsAzurePipelineBuild) {
} }
if (($BuildStep -ieq "all") -Or ($BuildStep -ieq "build")) { if (($BuildStep -ieq "all") -Or ($BuildStep -ieq "build")) {
& $nugetPath restore (Join-Path $PSScriptRoot "..\..\..\..\..\PowerToys.sln") & $nugetPath restore (Join-Path $PSScriptRoot "..\..\..\..\..\PowerToys.slnx")
Try { Try {
foreach ($config in $Configuration.Split(",")) { foreach ($config in $Configuration.Split(",")) {

View File

@@ -12,7 +12,7 @@ Tip: Add `D:\PowerToys\tools\build` to your PATH to use the wrappers anywhere.
## When to use which ## When to use which
1) `build-essentials.ps1` 1) `build-essentials.ps1`
- Restores NuGet for `PowerToys.sln` and builds essentials (runner, settings). - Restores NuGet for `PowerToys.slnx` and builds essentials (runner, settings).
- Auto-detects Platform; initializes VS Dev environment automatically. - Auto-detects Platform; initializes VS Dev environment automatically.
- Example (PowerShell): - Example (PowerShell):
- `./tools/build/build-essentials.ps1` - `./tools/build/build-essentials.ps1`

View File

@@ -113,7 +113,7 @@ function BuildProjectsInDirectory {
$files = @() $files = @()
try { try {
$files = Get-ChildItem -Path (Join-Path $DirectoryPath '*') -Include *.sln,*.csproj,*.vcxproj -File -ErrorAction SilentlyContinue $files = Get-ChildItem -Path (Join-Path $DirectoryPath '*') -Include *.sln,*.slnx,*.csproj,*.vcxproj -File -ErrorAction SilentlyContinue
} catch { } catch {
$files = @() $files = @()
} }

View File

@@ -3,7 +3,7 @@
Build essential native PowerToys projects (runner and settings), restoring NuGet packages first. Build essential native PowerToys projects (runner and settings), restoring NuGet packages first.
.DESCRIPTION .DESCRIPTION
Lightweight script to build a small set of essential C++ projects used by PowerToys' runner and native modules. This script first restores NuGet packages for the full solution (`PowerToys.sln`) and then builds the runner and settings projects. Intended for fast local builds during development. Lightweight script to build a small set of essential C++ projects used by PowerToys' runner and native modules. This script first restores NuGet packages for the full solution (`PowerToys.slnx`) and then builds the runner and settings projects. Intended for fast local builds during development.
.PARAMETER Platform .PARAMETER Platform
Target platform for the build (for example: 'x64', 'arm64'). If omitted the script will attempt to auto-detect the host platform. Target platform for the build (for example: 'x64', 'arm64'). If omitted the script will attempt to auto-detect the host platform.
@@ -21,7 +21,7 @@ Restores packages and builds the essentials in Release mode for ARM64, even if y
.NOTES .NOTES
- This script dot-sources `build-common.ps1` and uses the shared helper `RunMSBuild`. - This script dot-sources `build-common.ps1` and uses the shared helper `RunMSBuild`.
- It will call `RestoreThenBuild 'PowerToys.sln'` before building the essential projects to ensure NuGet packages are restored. - It will call `RestoreThenBuild 'PowerToys.slnx'` before building the essential projects to ensure NuGet packages are restored.
- The script attempts to locate the repository root automatically and can be run from any folder inside the repo. - The script attempts to locate the repository root automatically and can be run from any folder inside the repo.
#> #>
@@ -33,7 +33,7 @@ param (
# Find repository root starting from the script location # Find repository root starting from the script location
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
$repoRoot = $ScriptDir $repoRoot = $ScriptDir
while ($repoRoot -and -not (Test-Path (Join-Path $repoRoot "PowerToys.sln"))) { while ($repoRoot -and -not (Test-Path (Join-Path $repoRoot "PowerToys.slnx"))) {
$parent = Split-Path -Parent $repoRoot $parent = Split-Path -Parent $repoRoot
if ($parent -eq $repoRoot) { if ($parent -eq $repoRoot) {
Write-Error "Could not find PowerToys repository root." Write-Error "Could not find PowerToys repository root."
@@ -63,7 +63,7 @@ if (-not $Platform -or $Platform -eq '') {
} }
# Ensure solution packages are restored # Ensure solution packages are restored
RestoreThenBuild 'PowerToys.sln' '' $Platform $Configuration $true RestoreThenBuild 'PowerToys.slnx' '' $Platform $Configuration $true
# Build both runner and settings # Build both runner and settings
$ProjectsToBuild = @(".\src\runner\runner.vcxproj", ".\src\settings-ui\Settings.UI\PowerToys.Settings.csproj") $ProjectsToBuild = @(".\src\runner\runner.vcxproj", ".\src\settings-ui\Settings.UI\PowerToys.Settings.csproj")

View File

@@ -73,18 +73,18 @@ $repoRoot = $scriptDir
# Navigate up from the script location to find the repo root # Navigate up from the script location to find the repo root
# Script is typically in tools\build, so go up two levels # Script is typically in tools\build, so go up two levels
while ($repoRoot -and -not (Test-Path (Join-Path $repoRoot "PowerToys.sln"))) { while ($repoRoot -and -not (Test-Path (Join-Path $repoRoot "PowerToys.slnx"))) {
$parentDir = Split-Path -Parent $repoRoot $parentDir = Split-Path -Parent $repoRoot
if ($parentDir -eq $repoRoot) { if ($parentDir -eq $repoRoot) {
# Reached the root of the drive, PowerToys.sln not found # Reached the root of the drive, PowerToys.slnx not found
Write-Error "Could not find PowerToys repository root. Make sure this script is in the PowerToys repository." Write-Error "Could not find PowerToys repository root. Make sure this script is in the PowerToys repository."
exit 1 exit 1
} }
$repoRoot = $parentDir $repoRoot = $parentDir
} }
if (-not $repoRoot -or -not (Test-Path (Join-Path $repoRoot "PowerToys.sln"))) { if (-not $repoRoot -or -not (Test-Path (Join-Path $repoRoot "PowerToys.slnx"))) {
Write-Error "Could not locate PowerToys.sln. Please ensure this script is run from within the PowerToys repository." Write-Error "Could not locate PowerToys.slnx. Please ensure this script is run from within the PowerToys repository."
exit 1 exit 1
} }
@@ -102,7 +102,7 @@ if (Test-Path $cmdpalOutputPath) {
$commonArgs = '/p:CIBuild=true' $commonArgs = '/p:CIBuild=true'
# No local projects found (or continuing) - build full solution and tools # No local projects found (or continuing) - build full solution and tools
RestoreThenBuild 'PowerToys.sln' $commonArgs $Platform $Configuration RestoreThenBuild 'PowerToys.slnx' $commonArgs $Platform $Configuration
$msixSearchRoot = Join-Path $repoRoot "$Platform\$Configuration" $msixSearchRoot = Join-Path $repoRoot "$Platform\$Configuration"
$msixFiles = Get-ChildItem -Path $msixSearchRoot -Recurse -Filter *.msix | $msixFiles = Get-ChildItem -Path $msixSearchRoot -Recurse -Filter *.msix |
@@ -141,10 +141,10 @@ try {
Pop-Location Pop-Location
} }
RunMSBuild 'installer\PowerToysSetup.sln' "$commonArgs /t:restore /p:RestorePackagesConfig=true" $Platform $Configuration RunMSBuild 'installer\PowerToysSetup.slnx' "$commonArgs /t:restore /p:RestorePackagesConfig=true" $Platform $Configuration
RunMSBuild 'installer\PowerToysSetup.sln' "$commonArgs /m /t:PowerToysInstallerVNext /p:PerUser=$PerUser" $Platform $Configuration RunMSBuild 'installer\PowerToysSetup.slnx' "$commonArgs /m /t:PowerToysInstallerVNext /p:PerUser=$PerUser" $Platform $Configuration
RunMSBuild 'installer\PowerToysSetup.sln' "$commonArgs /m /t:PowerToysBootstrapperVNext /p:PerUser=$PerUser" $Platform $Configuration RunMSBuild 'installer\PowerToysSetup.slnx' "$commonArgs /m /t:PowerToysBootstrapperVNext /p:PerUser=$PerUser" $Platform $Configuration
Write-Host '[PIPELINE] Completed' Write-Host '[PIPELINE] Completed'

View File

@@ -6,7 +6,7 @@
- The template will be available in Visual Studio, when adding a new project, under the `Visual C++` tab. - The template will be available in Visual Studio, when adding a new project, under the `Visual C++` tab.
## Contributing ## Contributing
If you'd like to work on a PowerToy template, make required modifications to `\tools\project_template\ModuleTemplate.vcxproj` and then use the dedicated solution `PowerToyTemplate.sln` to export it as a template. Note that `ModuleTemplate.vcxproj` is actually a project template, therefore uncompilable, so we also have a dedicated `ModuleTemplateCompileTest.vcxproj` project referenced from the `PowerToys.sln` to help keeping the template sources up to date and verify it compiles correctly. If you'd like to work on a PowerToy template, make required modifications to `\tools\project_template\ModuleTemplate.vcxproj` and then use the dedicated solution `PowerToyTemplate.sln` to export it as a template. Note that `ModuleTemplate.vcxproj` is actually a project template, therefore uncompilable, so we also have a dedicated `ModuleTemplateCompileTest.vcxproj` project referenced from the `PowerToys.slnx` to help keeping the template sources up to date and verify it compiles correctly.
## Create a new PowerToy Module ## Create a new PowerToy Module
@@ -442,7 +442,7 @@ void ExamplePowertoy::save_settings() {
## Add a new PowerToy to the Installer ## Add a new PowerToy to the Installer
In the `installer` folder, open the `PowerToysSetup.sln` solution. In the `installer` folder, open the `PowerToysSetup.slnx` solution.
Under the `PowerToysSetup` project, edit `Product.wxs`. Under the `PowerToysSetup` project, edit `Product.wxs`.
You will need to add a component for your module DLL. Search for `Module_ShortcutGuide` to see where to add the component declaration and where to reference that declaration so the DLL is added to the installer. You will need to add a component for your module DLL. Search for `Module_ShortcutGuide` to see where to add the component declaration and where to reference that declaration so the DLL is added to the installer.
Each component requires a newly generated GUID (you can use the Visual Studio integrated tool to generate one). Each component requires a newly generated GUID (you can use the Visual Studio integrated tool to generate one).