mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 03:37:59 +01:00
Merge branch 'main' of https://github.com/microsoft/PowerToys into leilzh/fancyzonescli
This commit is contained in:
3
.github/actions/spell-check/expect.txt
vendored
3
.github/actions/spell-check/expect.txt
vendored
@@ -773,6 +773,7 @@ INITGUID
|
||||
INITTOLOGFONTSTRUCT
|
||||
INLINEPREFIX
|
||||
inlines
|
||||
Inno
|
||||
INPC
|
||||
inproc
|
||||
INPUTHARDWARE
|
||||
@@ -1629,6 +1630,7 @@ SKIPOWNPROCESS
|
||||
sku
|
||||
SLGP
|
||||
sln
|
||||
slnx
|
||||
SMALLICON
|
||||
smartphone
|
||||
smileys
|
||||
@@ -1847,6 +1849,7 @@ UNCPRIORITY
|
||||
UNDNAME
|
||||
UNICODETEXT
|
||||
unins
|
||||
Uninstaller
|
||||
uninstalls
|
||||
Uniquifies
|
||||
unitconverter
|
||||
|
||||
@@ -192,14 +192,14 @@ jobs:
|
||||
displayName: Verify XAML formatting
|
||||
|
||||
- pwsh: |-
|
||||
& '.pipelines/verifyNugetPackages.ps1' -solution '$(build.sourcesdirectory)\PowerToys.sln'
|
||||
displayName: Verify Nuget package versions for PowerToys.sln
|
||||
& '.pipelines/verifyNugetPackages.ps1' -solution '$(build.sourcesdirectory)\PowerToys.slnx'
|
||||
displayName: Verify Nuget package versions for PowerToys.slnx
|
||||
|
||||
- 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\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
|
||||
|
||||
- ${{ if eq(parameters.enablePackageCaching, true) }}:
|
||||
@@ -252,7 +252,7 @@ jobs:
|
||||
${{ else }}:
|
||||
displayName: Build PowerToys main project
|
||||
inputs:
|
||||
solution: 'PowerToys.sln'
|
||||
solution: 'PowerToys.slnx'
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
-restore -graph
|
||||
@@ -275,7 +275,7 @@ jobs:
|
||||
displayName: Generate DSC artifacts for ARM64
|
||||
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
|
||||
inputs:
|
||||
solution: PowerToys.sln
|
||||
solution: PowerToys.slnx
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
-restore
|
||||
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: nuget.config
|
||||
restoreSolution: PowerToys.sln
|
||||
restoreSolution: PowerToys.slnx
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\packages'
|
||||
|
||||
# Build all UI test projects if no specific modules are specified
|
||||
|
||||
@@ -35,7 +35,7 @@ steps:
|
||||
- task: VSBuild@1
|
||||
displayName: Build Shared Support DLLs
|
||||
inputs:
|
||||
solution: "**/installer/PowerToysSetup.sln"
|
||||
solution: "**/installer/PowerToysSetup.slnx"
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
/t:PowerToysSetupCustomActionsVNext;SilentFilesInUseBAFunction
|
||||
@@ -74,7 +74,7 @@ steps:
|
||||
- task: VSBuild@1
|
||||
displayName: 💻 Build VNext MSI
|
||||
inputs:
|
||||
solution: "**/installer/PowerToysSetup.sln"
|
||||
solution: "**/installer/PowerToysSetup.slnx"
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
-restore
|
||||
@@ -91,7 +91,7 @@ steps:
|
||||
- task: VSBuild@1
|
||||
displayName: 👤 Build VNext MSI
|
||||
inputs:
|
||||
solution: "**/installer/PowerToysSetup.sln"
|
||||
solution: "**/installer/PowerToysSetup.slnx"
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
/t:PowerToysInstallerVNext
|
||||
@@ -142,7 +142,7 @@ steps:
|
||||
- task: VSBuild@1
|
||||
displayName: 💻 Build VNext Bootstrapper
|
||||
inputs:
|
||||
solution: "**/installer/PowerToysSetup.sln"
|
||||
solution: "**/installer/PowerToysSetup.slnx"
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
-restore
|
||||
@@ -159,7 +159,7 @@ steps:
|
||||
- task: VSBuild@1
|
||||
displayName: 👤 Build VNext Bootstrapper
|
||||
inputs:
|
||||
solution: "**/installer/PowerToysSetup.sln"
|
||||
solution: "**/installer/PowerToysSetup.slnx"
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
/t:PowerToysBootstrapperVNext
|
||||
|
||||
@@ -55,3 +55,12 @@ steps:
|
||||
nugetConfigPath: '$(build.sourcesdirectory)\nuget.config'
|
||||
restoreSolution: '$(build.sourcesdirectory)\**\*.sln'
|
||||
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
|
||||
|
||||
@@ -243,6 +243,10 @@ _If you want to find diagnostic data events in the source code, these two links
|
||||
<th>Event Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdNotFound_EnableCmdNotFound</td>
|
||||
<td>Triggered when Command Not Found is enabled or disabled.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdNotFoundInstallEvent</td>
|
||||
<td>Triggered when a Command Not Found is installed.</td>
|
||||
@@ -257,6 +261,62 @@ _If you want to find diagnostic data events in the source code, these two links
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Command Palette
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<th>Event Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_BeginInvoke</td>
|
||||
<td>Triggered when the Command Palette is launched by the user.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_ColdLaunch</td>
|
||||
<td>Occurs when Command Palette starts for the first time (cold start).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_OpenPage</td>
|
||||
<td>Triggered when a page is opened within the Command Palette, tracking navigation depth.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_OpenUri</td>
|
||||
<td>Occurs when a URI is opened through the Command Palette, including whether it's a web URL.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_ReactivateInstance</td>
|
||||
<td>Triggered when an existing Command Palette instance is reactivated.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_RunCommand</td>
|
||||
<td>Logs when a command is executed through the Command Palette, including admin elevation status.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_RunQuery</td>
|
||||
<td>Triggered when a search query is performed, including result count and duration.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPalDismissedOnEsc</td>
|
||||
<td>Occurs when the Command Palette is dismissed by pressing the Escape key.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPalDismissedOnLostFocus</td>
|
||||
<td>Triggered when the Command Palette is dismissed due to losing focus.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPalHotkeySummoned</td>
|
||||
<td>Logs when the Command Palette is summoned via hotkey, distinguishing between global and context-specific hotkeys.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPalInvokeResult</td>
|
||||
<td>Records the result type of a Command Palette invocation.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPalProcessStarted</td>
|
||||
<td>Triggered when the Command Palette process is started.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Crop And Lock
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
@@ -735,6 +795,10 @@ _If you want to find diagnostic data events in the source code, these two links
|
||||
<th>Event Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.NewPlus_ChangedTemplateLocation</td>
|
||||
<td>Triggered when the template folder location is changed.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.NewPlus_EventCopyTemplate</td>
|
||||
<td>Triggered when an item from New+ is created (copied to the current directory).</td>
|
||||
@@ -743,6 +807,10 @@ _If you want to find diagnostic data events in the source code, these two links
|
||||
<td>Microsoft.PowerToys.NewPlus_EventCopyTemplateResult</td>
|
||||
<td>Logs the success of item creation (copying).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.NewPlus_EventOpenTemplates</td>
|
||||
<td>Triggered when the templates folder is opened.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.NewPlus_EventShowTemplateItems</td>
|
||||
<td>Triggered when the New+ context menu flyout is displayed.</td>
|
||||
@@ -928,12 +996,8 @@ _If you want to find diagnostic data events in the source code, these two links
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.ShortcutGuide_EnableGuide</td>
|
||||
<td>Triggered when Shortcut Guide is enabled.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.ShortcutGuide_HideGuide</td>
|
||||
<td>Occurs when Shortcut Guide is hidden from view.</td>
|
||||
<td>Microsoft.PowerToys.ShortcutGuide_GuideSession</td>
|
||||
<td>Logs a Shortcut Guide session including duration and how it was closed.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.ShortcutGuide_Settings</td>
|
||||
|
||||
3407
PowerToys.sln
3407
PowerToys.sln
File diff suppressed because it is too large
Load Diff
1041
PowerToys.slnx
Normal file
1041
PowerToys.slnx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -134,7 +134,7 @@ If you prefer, you can alternatively build prerequisite projects for the install
|
||||
|
||||
#### 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. 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\
|
||||
MSBuild -t:restore .\installer\PowerToysSetup.sln -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.sln /t:PowerToysBootstrapperVNext /p:Configuration=Release /p:Platform="x64"
|
||||
MSBuild -t:restore .\installer\PowerToysSetup.slnx -p:RestorePackagesConfig=true /p:Platform="x64" /p:Configuration=Release
|
||||
MSBuild -t:Restore -m .\installer\PowerToysSetup.slnx /t:PowerToysInstallerVNext /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
|
||||
|
||||
@@ -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
|
||||
3. Run the following command(don't forget to set the correct platform):
|
||||
```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
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@ Or reach out to "tools\build\BUILD-GUIDELINES.md"
|
||||
### Sample plain msbuild command
|
||||
```powershell
|
||||
# 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
|
||||
msbuild powertoys.sln -p:configuration=debug -p:platform=x64 -m
|
||||
# Build powertoys slnx
|
||||
msbuild powertoys.slnx -p:configuration=debug -p:platform=x64 -m
|
||||
|
||||
# dotnet project
|
||||
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 |
|
||||
|------|------------------|-------|
|
||||
| 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 |
|
||||
| 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 |
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
- 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`).
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ The module provides a user interface for configuring settings in the PowerToys S
|
||||
### Building and Testing
|
||||
|
||||
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
|
||||
4. Run PowerToys.exe from the output directory to test the module
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ FancyZones is divided into several projects:
|
||||
```
|
||||
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
|
||||
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
|
||||
- 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`).
|
||||
|
||||
>Note: notifications or other application windows, that are shown above the window under test, can disrupt the testing process.
|
||||
|
||||
@@ -11,7 +11,7 @@ Keyboard Manager consists of two main components:
|
||||
## Development Environment Setup
|
||||
|
||||
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
|
||||
4. Build the entire solution in Debug configuration
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ The module’s settings are exposed in the PowerToys Settings UI. Options includ
|
||||
3. Build the solution:
|
||||
|
||||
```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.
|
||||
|
||||
@@ -53,7 +53,7 @@ The Screen Ruler module consists of several components:
|
||||
|
||||
### 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
|
||||
3. From the Build menu, choose Build Solution
|
||||
4. The executable app for Screen Ruler is named PowerToys.MeasureToolUI.exe
|
||||
|
||||
@@ -19,7 +19,7 @@ Shortcut Guide is a PowerToy that displays an overlay of available keyboard shor
|
||||
## Build and Debug Instructions
|
||||
|
||||
### 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
|
||||
3. From the Build menu, choose Build Solution
|
||||
4. The executable is named PowerToys.ShortcutGuide.exe
|
||||
|
||||
@@ -80,7 +80,7 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and an
|
||||
|
||||
### 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`
|
||||
|
||||
### 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
|
||||
|
||||
- Open `PowerToys.sln` in Visual Studio.
|
||||
- Open `PowerToys.slnx` in Visual Studio.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
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 `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.
|
||||
|
||||
|
||||
@@ -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
|
||||
22
installer/PowerToysSetup.slnx
Normal file
22
installer/PowerToysSetup.slnx
Normal 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>
|
||||
@@ -135,8 +135,9 @@ public partial class App : Application
|
||||
try
|
||||
{
|
||||
var winget = new WinGetExtensionCommandsProvider();
|
||||
var callback = allApps.LookupApp;
|
||||
winget.SetAllLookup(callback);
|
||||
winget.SetAllLookup(
|
||||
query => allApps.LookupAppByPackageFamilyName(query, requireSingleMatch: true),
|
||||
query => allApps.LookupAppByProductCode(query, requireSingleMatch: true));
|
||||
services.AddSingleton<ICommandProvider>(winget);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -58,7 +58,7 @@ public class AllAppsCommandProviderTests : AppsTestBase
|
||||
var provider = new AllAppsCommandProvider(page);
|
||||
|
||||
// Act
|
||||
var result = provider.LookupApp(string.Empty);
|
||||
var result = provider.LookupAppByDisplayName(string.Empty);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
@@ -77,7 +77,7 @@ public class AllAppsCommandProviderTests : AppsTestBase
|
||||
await WaitForPageInitializationAsync();
|
||||
|
||||
// Act
|
||||
var result = provider.LookupApp("TestApp");
|
||||
var result = provider.LookupAppByDisplayName("TestApp");
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
@@ -97,7 +97,7 @@ public class AllAppsCommandProviderTests : AppsTestBase
|
||||
await WaitForPageInitializationAsync();
|
||||
|
||||
// Act
|
||||
var result = provider.LookupApp("NonExistentApp");
|
||||
var result = provider.LookupAppByDisplayName("NonExistentApp");
|
||||
|
||||
// Assert
|
||||
Assert.IsNull(result);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
using System;
|
||||
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.State;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
@@ -66,7 +68,71 @@ public partial class AllAppsCommandProvider : CommandProvider
|
||||
|
||||
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();
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ public sealed class AppItem
|
||||
|
||||
public string AppIdentifier { get; set; } = string.Empty;
|
||||
|
||||
public string? PackageFamilyName { get; set; }
|
||||
|
||||
public string? FullExecutablePath { get; set; }
|
||||
|
||||
public AppItem()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ public sealed partial class AppListItem : ListItem
|
||||
|
||||
public string AppIdentifier => _app.AppIdentifier;
|
||||
|
||||
public AppItem App => _app;
|
||||
|
||||
public AppListItem(AppItem app, bool useThumbnails, bool isPinned)
|
||||
{
|
||||
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 } });
|
||||
}
|
||||
|
||||
#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
|
||||
IconInfo? heroImage = null;
|
||||
if (_app.IsPackaged)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -558,6 +558,7 @@ public class UWPApplication : IUWPApplication
|
||||
IsPackaged = true,
|
||||
Commands = app.GetCommands(),
|
||||
AppIdentifier = app.GetAppIdentifier(),
|
||||
PackageFamilyName = app.Package.FamilyName,
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -1065,6 +1065,7 @@ public class Win32Program : IProgram
|
||||
DirPath = app.Location,
|
||||
Commands = app.GetCommands(),
|
||||
AppIdentifier = app.GetAppIdentifier(),
|
||||
FullExecutablePath = app.FullPath,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public partial class InstallPackageCommand : InvokableCommand
|
||||
{
|
||||
PackageInstallCommandState.Install => Icons.DownloadIcon,
|
||||
PackageInstallCommandState.Update => Icons.UpdateIcon,
|
||||
PackageInstallCommandState.Uninstall => Icons.CompletedIcon,
|
||||
PackageInstallCommandState.Uninstall => Icons.DeleteIcon,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
Name = InstallCommandState switch
|
||||
|
||||
@@ -194,46 +194,95 @@ public partial class InstallPackageListItem : ListItem
|
||||
var isInstalled = _package.InstalledVersion is not null;
|
||||
|
||||
var installedState = isInstalled ?
|
||||
(_package.IsUpdateAvailable ?
|
||||
PackageInstallCommandState.Update : PackageInstallCommandState.Uninstall) :
|
||||
(_package.IsUpdateAvailable ? PackageInstallCommandState.Update : PackageInstallCommandState.Uninstall) :
|
||||
PackageInstallCommandState.Install;
|
||||
|
||||
// might be an uninstall command
|
||||
InstallPackageCommand installCommand = new(_package, installedState);
|
||||
|
||||
if (isInstalled)
|
||||
if (_package.InstalledVersion is not null)
|
||||
{
|
||||
this.Icon = installCommand.Icon;
|
||||
this.Command = new NoOpCommand();
|
||||
#if DEBUG
|
||||
var installerType = _package.InstalledVersion.GetMetadata(PackageVersionMetadataField.InstallerType);
|
||||
Subtitle = installerType + " | " + Subtitle;
|
||||
#endif
|
||||
|
||||
List<IContextItem> contextMenu = [];
|
||||
CommandContextItem uninstallContextItem = new(installCommand)
|
||||
Command = installCommand;
|
||||
Icon = installedState switch
|
||||
{
|
||||
IsCritical = true,
|
||||
Icon = Icons.DeleteIcon,
|
||||
PackageInstallCommandState.Install => Icons.DownloadIcon,
|
||||
PackageInstallCommandState.Update => Icons.UpdateIcon,
|
||||
PackageInstallCommandState.Uninstall => Icons.CompletedIcon,
|
||||
_ => Icons.DownloadIcon,
|
||||
};
|
||||
|
||||
if (WinGetStatics.AppSearchCallback is not null)
|
||||
TryLocateAndAppendActionForApp(contextMenu);
|
||||
|
||||
MoreCommands = contextMenu.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var callback = WinGetStatics.AppSearchCallback;
|
||||
var installedApp = callback(_package.DefaultInstallVersion is null ? _package.Name : _package.DefaultInstallVersion.DisplayName);
|
||||
if (installedApp is not null)
|
||||
{
|
||||
this.Command = installedApp.Command;
|
||||
contextMenu = [.. installedApp.MoreCommands];
|
||||
_installCommand = new InstallPackageCommand(_package, installedState);
|
||||
_installCommand.InstallStateChanged += InstallStateChangedHandler;
|
||||
Command = _installCommand;
|
||||
Icon = _installCommand.Icon;
|
||||
}
|
||||
}
|
||||
|
||||
contextMenu.Add(uninstallContextItem);
|
||||
this.MoreCommands = contextMenu.ToArray();
|
||||
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 names = _package.InstalledVersion.PackageFamilyNames;
|
||||
for (var i = 0; i < names.Count; i++)
|
||||
{
|
||||
var installedAppByPfn = lookupByPackageName(names[i]);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find the app
|
||||
_installCommand = new InstallPackageCommand(_package, installedState);
|
||||
this.Command = _installCommand;
|
||||
var lookupByProductCode = WinGetStatics.AppSearchByProductCodeCallback;
|
||||
if (lookupByProductCode is not null)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
Icon = _installCommand.Icon;
|
||||
_installCommand.InstallStateChanged += InstallStateChangedHandler;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to retrieve app context menu items for package '{_package?.Name ?? "Unknown"}'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void InstallStateChangedHandler(object? sender, InstallPackageCommand e)
|
||||
|
||||
@@ -41,5 +41,9 @@ public partial class WinGetExtensionCommandsProvider : CommandProvider
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ internal static class WinGetStatics
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ if ($IsAzurePipelineBuild) {
|
||||
}
|
||||
|
||||
if (($BuildStep -ieq "all") -Or ($BuildStep -ieq "build")) {
|
||||
& $nugetPath restore (Join-Path $PSScriptRoot "..\..\..\..\..\PowerToys.sln")
|
||||
& $nugetPath restore (Join-Path $PSScriptRoot "..\..\..\..\..\PowerToys.slnx")
|
||||
|
||||
Try {
|
||||
foreach ($config in $Configuration.Split(",")) {
|
||||
|
||||
@@ -12,7 +12,7 @@ Tip: Add `D:\PowerToys\tools\build` to your PATH to use the wrappers anywhere.
|
||||
|
||||
## When to use which
|
||||
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.
|
||||
- Example (PowerShell):
|
||||
- `./tools/build/build-essentials.ps1`
|
||||
|
||||
@@ -113,7 +113,7 @@ function BuildProjectsInDirectory {
|
||||
|
||||
$files = @()
|
||||
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 {
|
||||
$files = @()
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Build essential native PowerToys projects (runner and settings), restoring NuGet packages first.
|
||||
|
||||
.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
|
||||
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
|
||||
- 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.
|
||||
#>
|
||||
|
||||
@@ -33,7 +33,7 @@ param (
|
||||
# Find repository root starting from the script location
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
$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
|
||||
if ($parent -eq $repoRoot) {
|
||||
Write-Error "Could not find PowerToys repository root."
|
||||
@@ -63,7 +63,7 @@ if (-not $Platform -or $Platform -eq '') {
|
||||
}
|
||||
|
||||
# Ensure solution packages are restored
|
||||
RestoreThenBuild 'PowerToys.sln' '' $Platform $Configuration $true
|
||||
RestoreThenBuild 'PowerToys.slnx' '' $Platform $Configuration $true
|
||||
|
||||
# Build both runner and settings
|
||||
$ProjectsToBuild = @(".\src\runner\runner.vcxproj", ".\src\settings-ui\Settings.UI\PowerToys.Settings.csproj")
|
||||
|
||||
@@ -73,18 +73,18 @@ $repoRoot = $scriptDir
|
||||
|
||||
# Navigate up from the script location to find the repo root
|
||||
# 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
|
||||
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."
|
||||
exit 1
|
||||
}
|
||||
$repoRoot = $parentDir
|
||||
}
|
||||
|
||||
if (-not $repoRoot -or -not (Test-Path (Join-Path $repoRoot "PowerToys.sln"))) {
|
||||
Write-Error "Could not locate PowerToys.sln. Please ensure this script is run from within the PowerToys repository."
|
||||
if (-not $repoRoot -or -not (Test-Path (Join-Path $repoRoot "PowerToys.slnx"))) {
|
||||
Write-Error "Could not locate PowerToys.slnx. Please ensure this script is run from within the PowerToys repository."
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ if (Test-Path $cmdpalOutputPath) {
|
||||
|
||||
$commonArgs = '/p:CIBuild=true'
|
||||
# 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"
|
||||
$msixFiles = Get-ChildItem -Path $msixSearchRoot -Recurse -Filter *.msix |
|
||||
@@ -141,10 +141,10 @@ try {
|
||||
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'
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- The template will be available in Visual Studio, when adding a new project, under the `Visual C++` tab.
|
||||
|
||||
## 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
|
||||
|
||||
@@ -442,7 +442,7 @@ void ExamplePowertoy::save_settings() {
|
||||
|
||||
## 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`.
|
||||
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).
|
||||
|
||||
Reference in New Issue
Block a user