Compare commits

..

28 Commits

Author SHA1 Message Date
Leilei Zhang
f23bd3ec2e check in custon action 2026-01-29 15:25:27 +08:00
Leilei Zhang
f2d25d8eef fix check 2026-01-29 15:22:45 +08:00
Kai Tao
6d4f56cd83 Always on top: Add transparent support for on topped window (#44815)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Transparency support (best-effort)
> Not every window can be made transparent. Transparency is applied on a
best-effort basis and depends on how the target app/window is built and
rendered.

## When it may not work
* Windows with special rendering pipelines (e.g., certain
hardware-accelerated / compositor-managed surfaces).
* Some tool/popup/owned windows where the foreground window isn’t the
actual surface being drawn.

## How it works (high-level)
* Resolve the best target window (preferring the top-level/root window
over transient children).
* Apply Windows’ standard layered-window alpha mechanism (per-window
opacity) to adjust transparency.
* When unpinned, Restore the original opacity/state when possible.

If transparency doesn’t change, it means the window doesn’t support this
mechanism in its current configuration.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: 
#43278 
#42929
#28773

<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed


https://github.com/user-attachments/assets/c97a87f2-3126-4e19-990f-8c684dbeb631

<img width="1119" height="426" alt="image"
src="https://github.com/user-attachments/assets/547671ee-81d3-4c94-8199-bf0c4b1b7760"
/>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-29 13:48:27 +08:00
Jiří Polášek
4986915dae CmdPal: Batch ViewModel property change notifications (#44545)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR introduces batching for property change notifications emitted by
Command Palette view models. It also adds a secondary notification path
that is guaranteed to execute on a background thread.

- Introduces **`BatchUpdateManager`**, which batches
`INotifyPropertyChanged` events from view models and replays them in a
coordinated way.
- Slightly reduces UI thread contention and allows related UI updates to
be applied together, reducing visual "tearing" in list items (when
title, subtitle and icon are updated separately with slight delay).
Batching won't mitigate all occurences, but its good enough and works
auto-magically.
- Adds a complementary background notification event that:
  - Is guaranteed to run on a background thread.
  - Fires before UI-thread notifications.
- Allows consumers to attach handlers without blocking COM out-of-proc
objects.

- Updates `TopLevelViewModel` to subscribe to the background property
change event instead of the UI-thread one.
- This avoids unintentionally shifting work onto the UI thread and
re-triggering expensive operations there.
- Previously, because `TopLevelViewModel` wraps another view model and
our view models raise `INPC` on the UI thread by default, its handler
was executing on the UI thread and re-raising the event as
`IListItem.PropertyChanged`, causing `FetchProperty` methods to run on
the UI thread again.
- Ideally, `TopLevelViewModel` should be reworked to address this more
cleanly, but that turned out to be a non-trivial change. This PR applies
a targeted mitigation in the meantime.








<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 21:56:11 -06:00
Jiří Polášek
cc2dce8816 CmdPal: replace custom fuzzy matching in Window Walker (#44807)
## Summary of the Pull Request

This PR replaces the custom search controller and fuzzy matching with
standard classes from the Extension SDK Toolkit.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 21:23:50 -06:00
Jiří Polášek
0de2af77ac CmdPal: Make Calculator Great Again (#44594)
## Summary of the Pull Request

This PR continues the tradition of alphabetical progress. After
[MBGA](#41961), we move on to **MCBA — Make Calculator Better Again!**

- Introduces limited automatic correction and completion of expressions.
- The goal is to allow uninterrupted typing and avoid disruptions when a
partially entered expression is temporarily invalid (which previously
caused the result to be replaced by an error message or hidden by the
fallback).
  - The implementation intentionally aims for a sweet spot:
    - Ignores trailing binary operators.
    - Automatically closes all opened parentheses.
- It is not exhaustive; for example, incomplete constants or functions
may still result in an invalid query.
- Copy current result to the search bar.
- Adds an option to copy the current result to the search bar when the
user types `=` at the end of the expression.
  - Adds a new menu item for the same action.
  - Fixes the **Save** command to also copy the result to the query.
- Adds support for the `factorial(x)` function and the `x!` expression.
- Factorial calculations are supported up to `170!` (limited by
`double`), but display is constrained by decimal conversion and allows
direct display of results up to `20!`.
- Adds support for the `sign(x)` function.
- Adds support for the `π` symbol as an alternative to the `pi`
constant.
- Adds a context menu item to the result list item and fallback that
displays the octal representation of the result.
- Implements beautification of the query:
- Converts technical symbols such as `*` or `/` to `×` or `÷`,
respectively.
- Not enabled for fallbacks for now, since the item text should match
the query to keep the score intact.
- Implements additional normalization of symbols in the query:
  - Percent: `%`, `%`, `﹪`
  - Minus: `−`, `-`, `–`, `—`
  - Factorial: `!`, `!`
- Multiplication: `*`, `×`, `∗`, `·`, `⋅`, `✕`, `✖`, `\u2062` (invisible
times)
  - Division: `/`, `÷`, ``, `:`
- Allows use of `²` and `³` as alternatives to `^2` and `^3`.
- Updates the unit test that was culture sensitive to force en-US output
(not an actual fix, but at least it clears false positive for now)
- Fixes pre-parsing of scientific notation to prevent capturing minus
sign as part of it.
- Fixes normalization/rounding of the result, so it can display small
values (the current solution turned it into a string with scientific
notation and couldn't parse it back).
- Updates test with new cases

## Pictures? Moving!

Previous behavior:


https://github.com/user-attachments/assets/ebcdcd85-797a-44f9-a8b1-a0f2f33c6b42

New behavior:


https://github.com/user-attachments/assets/5bd94663-a0d0-4d7d-8032-1030e79926c3





<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #43481
- [x] Closes: #43460
- [x] Closes: #42078
- [x] Closes: #41839
- [x] Closes: #39659
- [x] Closes: #40502
- [x] Related to: #41715
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 21:23:39 -06:00
Jiří Polášek
4694e99477 CmdPal: Upgrade FuzzyStringMatcher in the Command Palette Extensions SDK (#44809)
## Summary of the Pull Request

This PR upgrades the `FuzzyStringMatcher` used in the Command Palette
Extensions SDK with a focus on performance, memory efficiency, and
improved matching behavior, while preserving compatibility with the
existing API. This PR is a backwards compatible alternative to
precomputed fuzzy matcher introduces in another PR.

The new implementation is designed as a drop-in replacement. Any
behavioral differences are intentional and primarily related to improved
diacritic handling, scoring consistency, and correctness of highlight
positions.

Changes:
- Keeps the existing public API intact and preserves behavior in nearly
all cases.
- Enables diacritics-insensitive matching by default, improving results
across accented and non-English languages.
- Significantly improves performance, with measured speedups in the
range of ~5–20 times, depending on scenario and input size.
- Reduces heap allocations to near zero by using stack allocation and
pooled buffers instead of large per-match DP arrays.
- Simplifies and optimizes matching logic:
  - Folds the haystack only once per match.
  - Uses rolling DP buffers instead of `O(query × target)` tables.
- Replaces large match tables with a compact bitset when tracking
highlight positions.
- Improves consistency and correctness:
  - Normalizes path separators (`\` → `/`) during folding.
- Avoids returning highlight positions for PinYin-only matches where no
1:1 mapping exists.
- Introduces unit tests, including comparison tests against the legacy
implementation to validate compatibility.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44066
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 21:23:12 -06:00
Jiří Polášek
64cabc8789 CmdPal: Fix window centering when moving to a display with different DPI (#45057)
## Summary of the Pull Request

This PR fixes centering of main window, when the window also moves
between move display with a different DPI.

- The centered position was calculated using the current window width
and height, but those values change after the window is moved to
accommodate the new display’s DPI.
- Calculations have been refactored out of main window to a helper
class.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44932
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 21:21:11 -06:00
Jiří Polášek
989e005500 CmdPal: Run shutdown and restart commands in a hidden window (#45062)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #40621 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 21:20:52 -06:00
Jiří Polášek
5f124cec55 CmdPal: Cache and show information for disabled command providers (#44278)
## Summary of the Pull Request

This PR adds a cache of command provider information so we can show
providers even when the command provider isn’t loaded.

It also updates the description for disabled extensions on the
Extensions page to always include the extension name.

Finally, it adds a placeholder icon for cases where an extension icon
isn’t loaded. Note that this doesn’t address fully transparent icons
that some extensions may inherit from the default template.

Before:

<img width="1883" height="167" alt="image"
src="https://github.com/user-attachments/assets/7ccaa669-9516-4b57-9646-4e755d29d75c"
/>


After:

<img width="1873" height="190" alt="image"
src="https://github.com/user-attachments/assets/f29549c2-ddd5-4688-ba9c-d1abd4b523a0"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 21:19:25 -06:00
Jiří Polášek
8ec530c65e CmdPal: GEH per partes; part 1: error report builder, sanitizer and internals tools setting page (#44140)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR adds three parts of the original big bad global error handler
(error report builder, sanitization and internal tools UI).

### Error Report Generation

- `ErrorReportBuilder`: Produces a detailed, technical report with
system context.
- Comprehensive data: OS version, architecture, culture, app version,
elevation status, etc.
- Exception analysis: Coalesces nested exception messages and HRESULT
details for clearer diagnostics.

<details><summary>Example</summary>
<pre>

This is an error report generated by Windows Command Palette.
If you are seeing this, it means something went a little sideways in the
app.
You can help us fix it by filing a report at
https://aka.ms/powerToysReportBug.

(While you’re at it, give the details below a quick skim — just to make
sure there’s nothing personal you’d prefer not to share. It’s rare, but
sometimes little surprises sneak in.)
============================================================
Summary:
  Message:               Test exception; thrown from the UI thread
  Type:                  System.NotImplementedException
  Source:                Microsoft.CmdPal.UI
  Time:                  2025-08-25 18:54:44.3854569
  HRESULT:               0x80004001 (-2147467263)
  Context:               MainThreadException

Application:
  App version:           0.0.1.0
  Is elevated:           no

Environment:
  OS version:            Microsoft Windows 10.0.26120
  OS architecture:       X64
  Runtime identifier:    win-x64
  Framework:             .NET 9.0.8
  Process architecture:  X64
  Culture:               cs-CZ
  UI culture:            en-US

Stack Trace:
at
Microsoft.CmdPal.UI.Settings.InternalPage.ThrowPlainMainThreadException_Click(Object
sender, RoutedEventArgs e)
at
WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object
sender, RoutedEventArgs e)
at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr
thisPtr, IntPtr sender, IntPtr e)

------------------ Full Exception Details ------------------
System.NotImplementedException: Test exception; thrown from the UI
thread
at
Microsoft.CmdPal.UI.Settings.InternalPage.ThrowPlainMainThreadException_Click(Object
sender, RoutedEventArgs e)
at
WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object
sender, RoutedEventArgs e)
at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr
thisPtr, IntPtr sender, IntPtr e)

============================================================

</pre>
</details> 

Real-world example: #41362

### PII Sanitization Framework

- `ErrorReportSanitizer`: Multi-layer sanitization pipeline for
sensitive data.
- Nine specialized rule providers:
- `PiiRuleProvider`: Personally identifiable information (emails, phone
numbers, SSNs).
- `ProfilePathAndUsernameRuleProvider`: Windows user profiles and
usernames.
- `NetworkRuleProvider`: IP addresses, MAC addresses, network
identifiers.
- `SecretKeyValueRulesProvider`: API keys, tokens, passwords in
key/value formats.
  - `FilenameMaskRuleProvider`: Sensitive file paths and extensions.
  - `UrlRuleProvider`: URLs and web addresses.
  - `TokenRuleProvider`: JWT and other auth tokens.
  - `ConnectionStringRuleProvider`: Database connection strings.
- `EnvironmentPropertiesRuleProvider`: Environment variables and system
properties.

### Internals Tools Page

A page in settings available in non-CI-builds:

<img width="1305" height="745" alt="image"
src="https://github.com/user-attachments/assets/3145ecfd-997f-491d-8c8a-6096634b6045"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 21:09:37 -06:00
Jeremy Sinclair
f82afdf384 [Dev][Build] VS 2026 Support (#44304)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This PR updates the PowerToys solution to support **Visual Studio 2026
(PlatformToolset v145)**. It centralizes the build configuration,
updates the C++ language standards, and fixes an issue with a MouseJump
unit test that appears while using the VS 2026 supported build agent.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [x] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

**Build System & Configuration:**
- Updated `Cpp.Build.props` to use `v145` (VS 2026) as the default
`PlatformToolset`, with fall back to `v143` for VS 2022.
- Configured C++ Language Standard:
  - `stdcpplatest` for production projects.
- Removed explicit `<PlatformToolset>` definitions from individual
project files (approx. 37 modules) to inherit correctly from the central
`Cpp.Build.props`.

**Code Refactoring & Fixes:**
- Updated `DrawingHelperTests.cs` in MouseJump Unit Test to ease the
pixel difference tolerance. This became an issue after switching to the
new VS2026 build agent.
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- Validated successful compilation of the entire solution. Similar
updates have been made to the .NET 10 branch, but these are much cleaner
and will be merged into that branch once fully confirmed working.

---------

Co-authored-by: Kai Tao (from Dev Box) <kaitao@microsoft.com>
Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
2026-01-28 15:46:34 -08:00
Kai Tao
aa2ba0c325 0.97.1 change log (#45112)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

97.1 change log

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-28 15:04:00 +08:00
Kai Tao
f534e5b8e5 [ZoomIt] Show users full hotkey list in settings (#43073)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR enhances the ZoomIt settings UI by refactoring some of the XAML
code and putting instructions as part of the settingsexpanders.
Additionally, the alternate hotkey combinations are now shown too and
will be updated based on the configured hotkey.
so that **Users will now be able to see all the hotkeys**.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #42236
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

### ZoomIt Extended (Derived) Hotkeys

Feature | Base Key Property | Default Base Key | Derived Key Property |
XOR Logic | Default Derived Key | Description
-- | -- | -- | -- | -- | -- | --
LiveZoom | LiveZoomToggleKey | Ctrl+4 | LiveZoomToggleKeyDraw | XOR
Shift | Ctrl+Shift+4 | Enter drawing mode in LiveZoom
Record | RecordToggleKey | Ctrl+5 | RecordToggleKeyCrop | XOR Shift |
Ctrl+Shift+5 | Record selected region (crop)
Record | RecordToggleKey | Ctrl+5 | RecordToggleKeyWindow | XOR Alt |
Ctrl+Alt+5 | Record specific window
Snip | SnipToggleKey | Ctrl+6 | SnipToggleKeySave | XOR Shift |
Ctrl+Shift+6 | Snip and save to file
DemoType | DemoTypeToggleKey | Ctrl+7 | DemoTypeToggleKeyReset | XOR
Shift | Ctrl+Shift+7 | Rewind to previous segment


<img width="832" height="3679" alt="Frame 2018778631"
src="https://github.com/user-attachments/assets/bebddcd8-d705-4582-ae8a-c847cb1c3e88"
/>

---------

Signed-off-by: check-spelling-bot <check-spelling-bot@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Kai Tao <vanzue@users.noreply.github.com>
2026-01-28 10:37:22 +08:00
Jiří Polášek
08715a6e46 CmdPal: Allow list item context menu (#45086)
## Summary of the Pull Request

This PR enables pointer-invoked context menus for list items when the
list contains at least one item, including the primary item.

The command bar "More" button or Ctrl+K hotkey remain unaffected - the
menu is not accessible through those.

<img width="453" height="210" alt="image"
src="https://github.com/user-attachments/assets/af0f38e3-e1e7-4968-9e2d-6d9293785ab1"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45083
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-27 13:52:12 -06:00
Mike Hall
d26d9f745a CursorWrap improvements (#44936)
## Summary of the Pull Request
- Updated engine for better multi-monitor support.
- Closing the laptop lid will now update the monitor topology
- New settings/dropdown to support wrapping on horizontal, vertical, or
both

<img width="1103" height="643" alt="image"
src="https://github.com/user-attachments/assets/ff4f0835-a8ca-4603-9441-123b71747d5c"
/>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44820
- [x] Closes: #44864
- [x] Closes: #44952

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments
Feedback for CursorWrap shows that users want the ability to constrain
wrapping for horizontal only, vertical only, or both (default behavior).
This PR adds a new dropdown to CursorWrap settings to enable a user to
select the appropriate wrapping model.

## Validation Steps Performed
Local build and running on Surface Laptop 7 Pro - will also validate on
a multi-monitor setup.

---------

Co-authored-by: vanzue <vanzue@outlook.com>
2026-01-27 13:27:11 +08:00
Gordon Lam
6661adbd5c chore(prompts): add fix active PR comments prompt with scoped changes (#44996)
## Summary of the Pull Request
Enhance the active PR comments prompt to allow for scoped changes while
removing outdated model references from various prompt files.

## PR Checklist
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments
The changes include the addition of a new prompt for fixing active PR
comments with scoped changes, ensuring that only simple fixes are
applied. Additionally, references to the model 'GPT-5.1-Codex-Max' have
been removed from several prompt files to streamline the prompts.

## Validation Steps Performed
Manual validation of the new prompt functionality was conducted to
ensure it correctly identifies and resolves active PR comments.
```
2026-01-26 20:34:11 -08:00
Heiko
5ecb97b4e0 [Enterprise; Policy] Add policy for CursorWrap to ADMX (#45028)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Added missing policy definition.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44897
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [x] **Documentation updated:** See PR for issue #44484 

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-27 11:24:02 +08:00
Jiří Polášek
13ce5db6b1 CmdPal: Add solution filter for Microsoft.CmdPal.Ext.PowerToys (#45096)
## Summary of the Pull Request

This PR adds a new solution filter (.slnf) for the
Microsoft.CmdPal.Ext.PowerToys extension project and its dependencies.

This is added as a separate solution filter alongside
CommandPalette.slnf, since the extension is not directly dependent on
Command Palette. Instead, it relies on the public SDK distributed via
NuGet. It also depends on other PowerToys projects, which would
unnecessarily clutter CommandPalette.slnf.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-26 21:14:05 -06:00
Jiří Polášek
f0831742d6 CmdPal: Remove deadlock bait from AppListItem (#45076)
## Summary of the Pull Request

This PR removes a Task.Wait() call from lazy-loading AppListItem details
that could be invoked on the UI thread and lead to a deadlock.

It now follows the same pattern previously used for loading icons in the
same class, which has proven to work well.

Prevents #44938 from stepping on this landmine.

Cherry-picked from #44973.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #45074 
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-27 09:51:16 +08:00
Shawn Yuan
ea43974287 [Settings] [Advanced Paste] Upgrade advanced paste settings safely to fix settings ui crash (#44862)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request makes a minor fix in the `AdvancedPasteViewModel`
constructor to ensure the correct settings repository is used for null
checking. The change improves code correctness by verifying
`advancedPasteSettingsRepository` instead of the generic
`settingsRepository`.

- Fixed null check to use `advancedPasteSettingsRepository` instead of
`settingsRepository` in the `AdvancedPasteViewModel` constructor for
more accurate validation.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44835
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-26 15:28:59 +08:00
Gordon Lam
0b3dc089ac [Peek] Fix Space key triggering during file rename (#44845) (#44995)
Don't show error window when CurrentItem is null - just return silently.
This restores the original behavior where CaretVisible() detection in
GetSelectedItems() would suppress Peek by returning null, and no window
would be shown.

PR #44703 added an error window for virtual folders (Home/Recent), but
this also triggered when user was typing (rename, search, address bar),
stealing focus and cancelling the operation.

Fixes #44845

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
2026-01-26 15:20:07 +08:00
Shawn Yuan
4ba6fd2723 Add telemetry for tray icon (#44985)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request adds telemetry tracking for user interactions with the
application's tray icon. Specifically, it introduces new methods for
logging `left-click`, `right-click`, and `double-click` events, and
integrates these telemetry calls into the tray icon event handling
logic.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-26 09:44:10 +08:00
Shawn Yuan
086c63b6af [Settings] Fix right click menu display issue (#44982)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request updates the tray icon context menu logic to better
reflect the state of the "Quick Access" feature. The menu now
dynamically updates its items and labels based on whether Quick Access
is enabled or disabled, improving clarity for users.

**Menu behavior improvements:**

* The tray icon menu now reloads itself when the Quick Access setting
changes, ensuring the menu always matches the current state.
* The "Settings" menu item label changes to "Settings\tLeft-click" when
Quick Access is disabled, providing clearer instructions to users.
[[1]](diffhunk://#diff-e5efbda4c356e159a6ca82a425db84438ab4014d1d90377b98a2eb6d9632d32dR176-R179)
[[2]](diffhunk://#diff-7139ecb2cf76e472c574a155268c19e919e2cce05d9d345c50c1f1bffc939e1aR198-R248)
* The Quick Access menu item is removed from the context menu when the
feature is disabled, preventing confusion.

**Internal state tracking:**

* Added a new variable `last_quick_access_state` to track the previous
Quick Access state and trigger menu reloads only when necessary.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44810
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
- When Quick Access is disabled

<img width="1537" height="312" alt="image"
src="https://github.com/user-attachments/assets/5d51f24e-ccb4-4973-afaa-8b64cc35db87"
/>

- When Quick Access is enabled
<img width="1601" height="201" alt="image"
src="https://github.com/user-attachments/assets/56366d10-bcec-4892-b2d2-f8213ad726aa"
/>

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-23 14:47:35 +08:00
moooyo
d192672c74 fix: Improve Unicode normalization and add regex metachar tests (#44944)
Enhanced SanitizeAndNormalize to handle Unicode normalization more
robustly, ensuring correct buffer sizing and error handling. Added unit
tests for regex metacharacters `$` and `^` to verify correct replacement
behavior at string boundaries. Improves Unicode support and test
coverage for regex edge cases.

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44942 #44892
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng <yuleng@microsoft.com>
2026-01-23 14:43:21 +08:00
Kai Tao
60b8419366 Runner TrayIcon: Monochrome icon should adapt to windows theme instead of the app theme (#44931)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
As title
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: #44891
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
============ System light + App Light
<img width="903" height="239" alt="image"
src="https://github.com/user-attachments/assets/581606fb-99b5-4df9-a520-545a0c04676c"
/>
============ System Light + App Dark
<img width="991" height="239" alt="image"
src="https://github.com/user-attachments/assets/822009e9-57cf-452b-b3aa-f1cbc25883f8"
/>
============ System Dark + App Light
<img width="932" height="236" alt="image"
src="https://github.com/user-attachments/assets/98a56d48-31f0-4f75-95a4-8c7dc83c3866"
/>
============ System Dark + App Dark
<img width="903" height="236" alt="image"
src="https://github.com/user-attachments/assets/2500a0d5-6b27-403e-89b4-69b7d3b91e79"
/>
============
2026-01-23 10:47:19 +08:00
Kai Tao
d46a996fcd Cmdpal: use latest msix to install (#44886)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
We should install latest cmdpal msix
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #44860
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-23 09:58:53 +08:00
Jiří Polášek
395850389f CmdPal: Improve loading of application icons - part 1 (#44938)
## Summary of the Pull Request

This PR improves loading of application icons:

- Fixes loading of icons from internet shortcuts

## Pictures? Pictures!

<img width="683" height="399" alt="image"
src="https://github.com/user-attachments/assets/5e566648-7b1a-4254-8afd-557a321b19d6"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #44819
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-01-22 19:25:24 +01:00
883 changed files with 38434 additions and 9328 deletions

View File

@@ -565,7 +565,7 @@ perl(?:\s+-[a-zA-Z]\w*)+
regexp?\.MustCompile\((?:`[^`]*`|".*"|'.*')\)
# regex choice
\(\?:[^)]+\|[^)]+\)
# \(\?:[^)]+\|[^)]+\)
# proto
^\s*(\w+)\s\g{-1} =

View File

@@ -104,8 +104,12 @@
^src/common/ManagedCommon/ColorFormatHelper\.cs$
^src/common/notifications/BackgroundActivatorDLL/cpp\.hint$
^src/common/sysinternals/Eula/
^src/modules/cmdpal/Tests/Microsoft\.CommandPalette\.Extensions\.Toolkit\.UnitTests/FuzzyMatcherComparisonTests.cs$
^src/modules/cmdpal/Tests/Microsoft\.CommandPalette\.Extensions\.Toolkit\.UnitTests/FuzzyMatcherDiacriticsTests.cs$
^src/modules/cmdpal/doc/initial-sdk-spec/list-elements-mock-002\.pdn$
^src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage\.cs$
^src/modules/cmdpal/Microsoft\.CmdPal\.UI/Settings/InternalPage\.SampleData\.cs$
^src/modules/cmdpal/Tests/Microsoft\.CmdPal\.Core\.Common\.UnitTests/.*\.TestData\.cs$
^src/modules/colorPicker/ColorPickerUI/Shaders/GridShader\.cso$
^src/modules/launcher/Plugins/Microsoft\.PowerToys\.Run\.Plugin\.TimeDate/Properties/
^src/modules/MouseUtils/MouseJumpUI/MainForm\.resx$

View File

@@ -22,7 +22,6 @@ ADate
ADDSTRING
ADDUNDORECORD
ADifferent
adjacents
ADMINS
adml
admx
@@ -103,7 +102,6 @@ ASYNCWINDOWPLACEMENT
ASYNCWINDOWPOS
atl
ATRIOX
ATX
aumid
authenticode
AUTOBUDDY
@@ -220,10 +218,11 @@ CIELCh
cim
CImage
cla
claude
CLASSDC
classguid
classmethod
CLASSNOTAVAILABLE
claude
CLEARTYPE
clickable
clickonce
@@ -262,7 +261,6 @@ colorhistory
colorhistorylimit
COLORKEY
colorref
Convs
comctl
comdlg
comexp
@@ -283,6 +281,7 @@ CONTEXTHELP
CONTEXTMENUHANDLER
contractversion
CONTROLPARENT
Convs
copiedcolorrepresentation
coppied
copyable
@@ -298,7 +297,6 @@ cpcontrols
cph
cplusplus
CPower
cppcoreguidelines
cpptools
cppvsdbg
cppwinrt
@@ -327,7 +325,7 @@ CURRENTDIR
CURSORINFO
cursorpos
CURSORSHOWING
CURSORWRAP
cursorwrap
customaction
CUSTOMACTIONTEST
CUSTOMFORMATPLACEHOLDER
@@ -350,12 +348,14 @@ datareader
datatracker
dataversion
Dayof
dbcc
DBID
DBLCLKS
DBLEPSILON
DBPROP
DBPROPIDSET
DBPROPSET
DBT
DCBA
DCOM
DComposition
@@ -373,8 +373,7 @@ DEFAULTICON
defaultlib
DEFAULTONLY
DEFAULTSIZE
DEFAULTTONEAREST
Defaulttonearest
defaulttonearest
DEFAULTTONULL
DEFAULTTOPRIMARY
DEFERERASE
@@ -396,14 +395,19 @@ DESKTOPVERTRES
devblogs
devdocs
devenv
DEVICEINTERFACE
devicetype
DEVINTERFACE
devmgmt
DEVMODE
DEVMODEW
DEVNODES
devpal
DEVTYP
dfx
DIALOGEX
digicert
diffs
digicert
DINORMAL
DISABLEASACTIONKEY
DISABLENOSCROLL
@@ -546,7 +550,6 @@ fdx
FErase
fesf
FFFF
FInc
Figma
FILEEXPLORER
fileexploreraddons
@@ -567,6 +570,7 @@ FILESYSPATH
Filetime
FILEVERSION
FILTERMODE
FInc
findfast
findmymouse
FIXEDFILEINFO
@@ -593,6 +597,7 @@ frm
FROMTOUCH
fsanitize
fsmgmt
ftps
fuzzingtesting
fxf
FZE
@@ -668,13 +673,14 @@ HCRYPTPROV
hcursor
hcwhite
hdc
HDEVNOTIFY
hdr
hdrop
hdwwiz
Helpline
helptext
HGFE
hgdiobj
HGFE
hglobal
hhk
HHmmssfff
@@ -750,9 +756,9 @@ HWNDPARENT
HWNDPREV
hyjiacan
IAI
icf
ICONERROR
ICONLOCATION
icf
IDCANCEL
IDD
idk
@@ -843,8 +849,8 @@ jeli
jfif
jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi
jjw
JOBOBJECT
jobject
JOBOBJECT
jpe
jpnime
Jsons
@@ -888,6 +894,7 @@ Ldr
LEFTALIGN
LEFTSCROLLBAR
LEFTTEXT
leftclick
LError
LEVELID
LExit
@@ -930,9 +937,9 @@ LOWORD
lparam
LPBITMAPINFOHEADER
LPCFHOOKPROC
lpch
LPCITEMIDLIST
LPCLSID
lpch
lpcmi
LPCMINVOKECOMMANDINFO
LPCREATESTRUCT
@@ -948,6 +955,7 @@ LPMONITORINFO
LPOSVERSIONINFOEXW
LPQUERY
lprc
LPrivate
LPSAFEARRAY
lpstr
lpsz
@@ -957,7 +965,6 @@ lptpm
LPTR
LPTSTR
lpv
LPrivate
LPW
lpwcx
lpwndpl
@@ -1001,13 +1008,13 @@ mber
MBM
MBR
Mbuttondown
mcp
MDICHILD
MDL
mdtext
mdtxt
mdwn
meme
mcp
memicmp
MENUITEMINFO
MENUITEMINFOW
@@ -1042,8 +1049,8 @@ mmi
mmsys
mobileredirect
mockapi
modelcontextprotocol
MODALFRAME
modelcontextprotocol
MODESPRUNED
MONITORENUMPROC
MONITORINFO
@@ -1087,9 +1094,9 @@ MSLLHOOKSTRUCT
Mso
msrc
msstore
mstsc
msvcp
MT
mstsc
MTND
MULTIPLEUSE
multizone
@@ -1099,11 +1106,11 @@ muxxc
muxxh
MVPs
mvvm
myorg
myrepo
MVVMTK
MWBEx
MYICON
myorg
myrepo
NAMECHANGE
namespaceanddescendants
nao
@@ -1244,10 +1251,8 @@ opencode
OPENFILENAME
openrdp
opensource
openxmlformats
ollama
onnx
openurl
openxmlformats
OPTIMIZEFORINVOKE
ORPHANEDDIALOGTITLE
ORSCANS
@@ -1325,7 +1330,7 @@ phwnd
pici
pidl
PIDLIST
PII
pii
pinfo
pinvoke
pipename
@@ -1464,7 +1469,6 @@ rbhid
Rbuttondown
rclsid
RCZOOMIT
remotedesktop
rdp
RDW
READMODE
@@ -1493,6 +1497,7 @@ remappings
REMAPSUCCESSFUL
REMAPUNSUCCESSFUL
Remotable
remotedesktop
remoteip
Removelnk
renamable
@@ -1526,8 +1531,9 @@ RIGHTSCROLLBAR
riid
RKey
RNumber
rop
rollups
ROOTOWNER
rop
ROUNDSMALL
ROWSETEXT
rpcrt
@@ -1711,6 +1717,7 @@ srw
srwlock
sse
ssf
Ssn
sszzz
STACKFRAME
stackoverflow
@@ -1760,15 +1767,13 @@ SUBMODULEUPDATE
subresource
Superbar
sut
swe
svchost
SVGIn
SVGIO
svgz
SVSI
SWFO
SWP
Swp
swp
SWPNOSIZE
SWPNOZORDER
SWRESTORE
@@ -1787,8 +1792,7 @@ SYSKEY
syskeydown
SYSKEYUP
SYSLIB
SYSMENU
Sysmenu
sysmenu
systemai
SYSTEMAPPS
SYSTEMMODAL
@@ -1823,6 +1827,7 @@ TEXTBOXNEWLINE
textextractor
TEXTINCLUDE
tfopen
tgamma
tgz
THEMECHANGED
themeresources
@@ -1892,9 +1897,9 @@ uitests
UITo
ULONGLONG
Ultrawide
ums
UMax
UMin
ums
uncompilable
UNCPRIORITY
UNDNAME

View File

@@ -1,6 +1,5 @@
---
agent: 'agent'
model: 'GPT-5.1-Codex-Max'
description: 'Generate an 80-character git commit title for the local diff'
---

View File

@@ -1,6 +1,5 @@
---
agent: 'agent'
model: 'GPT-5.1-Codex-Max'
description: 'Generate a PowerToys-ready pull request description from the local diff'
---

View File

@@ -1,6 +1,5 @@
---
agent: 'agent'
model: 'GPT-5.1-Codex-Max'
description: 'Execute the fix for a GitHub issue using the previously generated implementation plan'
---

View File

@@ -0,0 +1,70 @@
---
description: 'Fix active pull request comments with scoped changes'
name: 'fix-pr-active-comments'
agent: 'agent'
argument-hint: 'PR number or active PR URL'
---
# Fix Active PR Comments
## Mission
Resolve active pull request comments by applying only simple fixes. For complex refactors, write a plan instead of changing code.
## Scope & Preconditions
- You must have an active pull request context or a provided PR number.
- Only implement simple changes. Do not implement large refactors.
- If required context is missing, request it and stop.
## Inputs
- Required: ${input:pr_number:PR number or URL}
- Optional: ${input:comment_scope:files or areas to focus on}
- Optional: ${input:fixing_guidelines:additional fixing guidelines from the user}
## Workflow
1. Locate all active (unresolved) PR review comments for the given PR.
2. For each comment, classify the change scope:
- Simple change: limited edits, localized fix, low risk, no broad redesign.
- Large refactor: multi-file redesign, architecture change, or risky behavior change.
3. For each large refactor request:
- Do not modify code.
- Write a planning document to Generated Files/prReview/${input:pr_number}/fixPlan/.
4. For each simple change request:
- Implement the fix with minimal edits.
- Run quick checks if needed.
- Commit and push the change.
5. For comments that seem invalid, unclear, or not applicable (even if simple):
- Do not change code.
- Add the item to a summary table in Generated Files/prReview/${input:pr_number}/fixPlan/overview.md.
- Consult back to the end user in a friendly, polite tone.
6. Respond to each comment that you fixed:
- Reply in the active conversation.
- Use a polite or friendly tone.
- Keep the response under 200 words.
- Resolve the comment after replying.
## Output Expectations
- Simple fixes: code changes committed and pushed.
- Large refactors: a plan file saved to Generated Files/prReview/${input:pr_number}/fixPlan/.
- Invalid or unclear comments: captured in Generated Files/prReview/${input:pr_number}/fixPlan/overview.md.
- Each fixed comment has a reply under 200 words and is resolved.
## Plan File Template
Use this template for each large refactor item:
# Fix Plan: <short title>
## Context
- Comment link:
- Impacted areas:
## Overview Table Template
Use this table in Generated Files/prReview/${input:pr_number}/fixPlan/overview.md:
| Comment link | Summary | Reason not applied | Suggested follow-up |
| --- | --- | --- | --- |
| | | | |
## Quality Assurance
- Verify plan file path exists.
- Ensure no code changes were made for large refactor items.
- Confirm replies are under 200 words and comments are resolved.

View File

@@ -1,6 +1,5 @@
---
agent: 'agent'
model: 'GPT-5.1-Codex-Max'
description: 'Resolve Code scanning / check-spelling comments on the active PR'
---

View File

@@ -1,6 +1,5 @@
---
agent: 'agent'
model: 'GPT-5.1-Codex-Max'
description: 'Review a GitHub issue, score it (0-100), and generate an implementation plan'
---

View File

@@ -1,6 +1,5 @@
---
agent: 'agent'
model: 'GPT-5.1-Codex-Max'
description: 'Perform a comprehensive PR review with per-step Markdown and machine-readable outputs'
---

View File

@@ -31,59 +31,82 @@
"Common.Search.dll",
"PowerToys.AlwaysOnTop.exe",
"PowerToys.AlwaysOnTopModuleInterface.dll",
"PowerToys.CmdNotFoundModuleInterface.dll",
"PowerToys.ColorPicker.dll",
"PowerToys.ColorPickerUI.dll",
"PowerToys.ColorPickerUI.exe",
"PowerToys.CropAndLockModuleInterface.dll",
"PowerToys.CropAndLock.exe",
"PowerToys.PowerOCRModuleInterface.dll",
"PowerToys.PowerOCR.dll",
"PowerToys.PowerOCR.exe",
"PowerToys.AdvancedPasteModuleInterface.dll",
"WinUI3Apps\\PowerToys.AdvancedPaste.exe",
"WinUI3Apps\\PowerToys.AdvancedPaste.dll",
"PowerToys.AwakeModuleInterface.dll",
"PowerToys.Awake.exe",
"PowerToys.Awake.dll",
"PowerToys.FancyZonesEditor.exe",
"PowerToys.FancyZonesEditor.dll",
"PowerToys.FancyZonesEditorCommon.dll",
"PowerToys.FancyZonesModuleInterface.dll",
"PowerToys.FancyZones.exe",
"FancyZonesCLI.exe",
"FancyZonesCLI.dll",
"PowerToys.GcodePreviewHandler.dll",
"PowerToys.GcodePreviewHandler.exe",
"PowerToys.GcodePreviewHandlerCpp.dll",
"PowerToys.GcodeThumbnailProvider.dll",
"PowerToys.GcodeThumbnailProvider.exe",
"PowerToys.GcodeThumbnailProviderCpp.dll",
"PowerToys.BgcodePreviewHandler.dll",
"PowerToys.BgcodePreviewHandler.exe",
"PowerToys.BgcodePreviewHandlerCpp.dll",
"PowerToys.BgcodeThumbnailProvider.dll",
"PowerToys.BgcodeThumbnailProvider.exe",
"PowerToys.BgcodeThumbnailProviderCpp.dll",
"PowerToys.ManagedTelemetry.dll",
"PowerToys.MarkdownPreviewHandler.dll",
"PowerToys.MarkdownPreviewHandler.exe",
"PowerToys.MarkdownPreviewHandlerCpp.dll",
"PowerToys.MonacoPreviewHandler.dll",
"PowerToys.MonacoPreviewHandler.exe",
"PowerToys.MonacoPreviewHandlerCpp.dll",
"PowerToys.PdfPreviewHandler.dll",
"PowerToys.PdfPreviewHandler.exe",
"PowerToys.PdfPreviewHandlerCpp.dll",
"PowerToys.PdfThumbnailProvider.dll",
"PowerToys.PdfThumbnailProvider.exe",
"PowerToys.PdfThumbnailProviderCpp.dll",
"PowerToys.powerpreview.dll",
"PowerToys.PreviewHandlerCommon.dll",
"PowerToys.QoiPreviewHandler.dll",
"PowerToys.QoiPreviewHandler.exe",
"PowerToys.QoiPreviewHandlerCpp.dll",
"PowerToys.QoiThumbnailProvider.dll",
"PowerToys.QoiThumbnailProvider.exe",
"PowerToys.QoiThumbnailProviderCpp.dll",
"PowerToys.StlThumbnailProvider.dll",
"PowerToys.StlThumbnailProvider.exe",
"PowerToys.StlThumbnailProviderCpp.dll",
"PowerToys.SvgPreviewHandler.dll",
"PowerToys.SvgPreviewHandler.exe",
"PowerToys.SvgPreviewHandlerCpp.dll",
"PowerToys.SvgThumbnailProvider.dll",
"PowerToys.SvgThumbnailProvider.exe",
"PowerToys.SvgThumbnailProviderCpp.dll",
"WinUI3Apps\\PowerToys.HostsModuleInterface.dll",
"WinUI3Apps\\PowerToys.HostsUILib.dll",
"WinUI3Apps\\PowerToys.Hosts.dll",
"WinUI3Apps\\PowerToys.Hosts.exe",
@@ -106,6 +129,7 @@
"WinUI3Apps\\PowerToys.QuickAccess.exe",
"WinUI3Apps\\PowerToys.Settings.UI.Controls.dll",
"WinUI3Apps\\PowerToys.EnvironmentVariablesModuleInterface.dll",
"WinUI3Apps\\PowerToys.EnvironmentVariablesUILib.dll",
"WinUI3Apps\\PowerToys.EnvironmentVariables.dll",
"WinUI3Apps\\PowerToys.EnvironmentVariables.exe",
@@ -118,6 +142,7 @@
"PowerToys.ImageResizerContextMenu.dll",
"ImageResizerContextMenuPackage.msix",
"PowerToys.LightSwitchModuleInterface.dll",
"LightSwitchService\\PowerToys.LightSwitchService.exe",
"PowerToys.KeyboardManager.dll",
@@ -153,6 +178,7 @@
"RunPlugins\\WebSearch\\Community.PowerToys.Run.Plugin.WebSearch.dll",
"RunPlugins\\WindowsTerminal\\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.dll",
"WinUI3Apps\\PowerToys.MeasureToolModuleInterface.dll",
"WinUI3Apps\\PowerToys.MeasureToolCore.dll",
"WinUI3Apps\\PowerToys.MeasureToolUI.dll",
"WinUI3Apps\\PowerToys.MeasureToolUI.exe",
@@ -168,6 +194,7 @@
"PowerToys.MouseWithoutBorders.dll",
"PowerToys.MouseWithoutBorders.exe",
"PowerToys.MouseWithoutBordersModuleInterface.dll",
"PowerToys.MouseWithoutBordersService.dll",
"PowerToys.MouseWithoutBordersService.exe",
"PowerToys.MouseWithoutBordersHelper.dll",
@@ -180,6 +207,7 @@
"PowerAccent.Core.dll",
"PowerToys.PowerAccent.dll",
"PowerToys.PowerAccent.exe",
"PowerToys.PowerAccentModuleInterface.dll",
"PowerToys.PowerAccentKeyboardService.dll",
"WinUI3Apps\\PowerToys.PowerRenameExt.dll",
@@ -194,6 +222,7 @@
"PowerToys.WorkspacesEditor.dll",
"PowerToys.WorkspacesLauncherUI.exe",
"PowerToys.WorkspacesLauncherUI.dll",
"PowerToys.WorkspacesModuleInterface.dll",
"PowerToys.WorkspacesCsharpLibrary.dll",
"WinUI3Apps\\PowerToys.RegistryPreviewExt.dll",
@@ -202,13 +231,16 @@
"WinUI3Apps\\PowerToys.RegistryPreview.exe",
"PowerToys.ShortcutGuide.exe",
"PowerToys.ShortcutGuideModuleInterface.dll",
"PowerToys.ZoomIt.exe",
"PowerToys.ZoomItModuleInterface.dll",
"PowerToys.ZoomItSettingsInterop.dll",
"WinUI3Apps\\PowerToys.Settings.dll",
"WinUI3Apps\\PowerToys.Settings.exe",
"PowerToys.CmdPalModuleInterface.dll",
"CmdPalKeyboardService.dll",
"PowerToys.ModuleContracts.dll",
"Awake.ModuleServices.dll",

View File

@@ -35,7 +35,9 @@ stages:
${{ else }}:
name: SHINE-OSS-L
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
demands: ImageOverride -equals SHINE-VS18-Preview
${{ else }}:
demands: ImageOverride -equals SHINE-VS18-Latest
buildPlatforms:
- ${{ parameters.platform }}
buildConfigurations: [Release]

View File

@@ -51,7 +51,9 @@ extends:
pool:
name: SHINE-INT-S
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
demands: ImageOverride -equals SHINE-VS18-Preview
${{ else }}:
demands: ImageOverride -equals SHINE-VS18-Latest
os: windows
sdl:
tsa:
@@ -74,7 +76,9 @@ extends:
demands:
# Our INT agents have a large disk mounted at P:\
- ${{ if eq(parameters.useVSPreview, true) }}:
- ImageOverride -equals SHINE-VS17-Preview
- ImageOverride -equals SHINE-VS18-Latest-Preview
- ${{ else }}:
- ImageOverride -equals SHINE-VS18-Latest
os: windows
variables:
IsPipeline: 1 # The installer uses this to detect whether it should pick up localizations

View File

@@ -253,7 +253,7 @@ jobs:
displayName: Build PowerToys main project
inputs:
solution: 'PowerToys.slnx'
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
-restore -graph
/p:RestorePackagesConfig=true
@@ -276,7 +276,7 @@ jobs:
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
inputs:
solution: PowerToys.slnx
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
-restore
/p:Configuration=$(BuildConfiguration)
@@ -338,7 +338,7 @@ jobs:
displayName: Build BugReportTool
inputs:
solution: '**/tools/BugReportTool/BugReportTool.sln'
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
-restore -graph
/p:RestorePackagesConfig=true
@@ -359,7 +359,7 @@ jobs:
displayName: Build StylesReportTool
inputs:
solution: '**/tools/StylesReportTool/StylesReportTool.sln'
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
-restore -graph
/p:RestorePackagesConfig=true
@@ -381,7 +381,7 @@ jobs:
displayName: Publish ${{ project }} for Packaging
inputs:
solution: ${{ project }}
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
/target:Publish
/graph

View File

@@ -82,7 +82,7 @@ jobs:
displayName: Build UI Test Projects
inputs:
solution: '**/*UITest*.csproj'
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
-restore
-graph
@@ -103,7 +103,7 @@ jobs:
displayName: 'Build UI Test Module: ${{ module }}'
inputs:
solution: '**/*${{ module }}*.csproj'
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
-restore
-graph

View File

@@ -49,7 +49,9 @@ stages:
${{ else }}:
name: SHINE-OSS-L
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
demands: ImageOverride -equals SHINE-VS18-Preview
${{ else }}:
demands: ImageOverride -equals SHINE-VS18-Latest
buildPlatforms:
- ${{ platform }}
buildConfigurations: [Release]

View File

@@ -29,7 +29,9 @@ stages:
${{ else }}:
name: SHINE-OSS-L
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
demands: ImageOverride -equals SHINE-VS18-Preview
${{ else }}:
demands: ImageOverride -equals SHINE-VS18-Latest
buildPlatforms:
- ${{ parameters.platform }}
buildConfigurations: [Release]

View File

@@ -36,7 +36,7 @@ steps:
displayName: Build Shared Support DLLs
inputs:
solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
/t:PowerToysSetupCustomActionsVNext;SilentFilesInUseBAFunction
/p:RunBuildEvents=true;RestorePackagesConfig=true;CIBuild=true
@@ -75,7 +75,7 @@ steps:
displayName: 💻 Build VNext MSI
inputs:
solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
-restore
/t:PowerToysInstallerVNext
@@ -92,7 +92,7 @@ steps:
displayName: 👤 Build VNext MSI
inputs:
solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
/t:PowerToysInstallerVNext
/p:RunBuildEvents=false;PerUser=true;BuildProjectReferences=false;CIBuild=true
@@ -143,7 +143,7 @@ steps:
displayName: 💻 Build VNext Bootstrapper
inputs:
solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
-restore
/t:PowerToysBootstrapperVNext
@@ -160,7 +160,7 @@ steps:
displayName: 👤 Build VNext Bootstrapper
inputs:
solution: "**/installer/PowerToysSetup.slnx"
vsVersion: 17.0
vsVersion: 18.0
msbuildArgs: >-
/t:PowerToysBootstrapperVNext
/p:PerUser=true;BuildProjectReferences=false;CIBuild=true

View File

@@ -1,9 +1,16 @@
$VSInstances = ([xml](& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -include packages -format xml))
# Build common vswhere base arguments
$vsWhereBaseArgs = @('-latest', '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64')
if ($env:VCWhereExtraVersionTarget) {
# Add version target if specified (e.g., '-version [18.0,19.0)' for VS2026)
$vsWhereBaseArgs += $env:VCWhereExtraVersionTarget.Split(' ')
}
$VSInstances = ([xml](& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' @vsWhereBaseArgs -include packages -format xml))
$VSPackages = $VSInstances.instances.instance.packages.package
$LatestVCPackage = ($VSPackages | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
$LatestVCToolsVersion = $LatestVCPackage.version;
$VSRoot = (& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property 'resolvedInstallationPath')
$VSRoot = (& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' @vsWhereBaseArgs -property 'resolvedInstallationPath')
$VCToolsRoot = Join-Path $VSRoot "VC\Tools\MSVC"
# We have observed a few instances where the VC tools package version actually
@@ -24,5 +31,12 @@ If ($Null -Eq (Get-Item $PackageVCToolPath -ErrorAction:Ignore)) {
}
Write-Output "Latest VCToolsVersion: $LatestVCToolsVersion"
Write-Output "Updating VCToolsVersion environment variable for job"
Write-Output "##vso[task.setvariable variable=VCToolsVersion]$LatestVCToolsVersion"
# VS2026 (MSVC 14.50+) doesn't need explicit VCToolsVersion - let MSBuild auto-select
$MajorMinorVersion = [Version]::Parse($LatestVCToolsVersion)
If ($MajorMinorVersion.Major -eq 14 -and $MajorMinorVersion.Minor -ge 50) {
Write-Output "VS2026 detected (MSVC 14.50+). Skipping VCToolsVersion override to allow MSBuild auto-selection."
} Else {
Write-Output "Updating VCToolsVersion environment variable for job"
Write-Output "##vso[task.setvariable variable=VCToolsVersion]$LatestVCToolsVersion"
}

View File

@@ -40,7 +40,7 @@ These instruction files are automatically applied when working in their respecti
### Prerequisites
- Visual Studio 2022 17.4+
- Visual Studio 2022 17.4+ or Visual Studio 2026
- Windows 10 1803+ (April 2018 Update or newer)
- Initialize submodules once: `git submodule update --init --recursive`

View File

@@ -2,17 +2,6 @@
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Generate version data -->
<Target Name="GenerateVersionData" BeforeTargets="PrepareForBuild">
<ItemGroup>
<HeaderLines Include="#pragma once" />
<HeaderLines Include="#define VERSION_MAJOR $(Version.Split('.')[0])" />
<HeaderLines Include="#define VERSION_MINOR $(Version.Split('.')[1])" />
<HeaderLines Include="#define VERSION_REVISION $(Version.Split('.')[2])" />
</ItemGroup>
<WriteLinesToFile File="Generated Files\version_gen.h" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
</Target>
<!-- Project configurations -->
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
@@ -62,7 +51,7 @@
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<WarningLevel>Level4</WarningLevel>
<DisableSpecificWarnings>4679;5271;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<DisableSpecificWarnings>4679;4706;4874;5271;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<DisableAnalyzeExternal >true</DisableAnalyzeExternal>
<ExternalWarningLevel>TurnOffAllWarnings</ExternalWarningLevel>
<ConformanceMode>false</ConformanceMode>
@@ -121,6 +110,7 @@
<!-- Props that are constant for both Debug and Release configurations -->
<PropertyGroup Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '18.0'">v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<DesktopCompatible>true</DesktopCompatible>
<SpectreMitigation>Spectre</SpectreMitigation>

View File

@@ -17,6 +17,7 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/COMUtils/COMUtils.vcxproj" Id="7319089e-46d6-4400-bc65-e39bdf1416ee" />
<Project Path="src/common/Display/Display.vcxproj" Id="caba8dfb-823b-4bf2-93ac-3f31984150d9" />
<Project Path="src/common/FilePreviewCommon/FilePreviewCommon.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
@@ -54,6 +55,8 @@
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/UnitTests-CommonLib/UnitTests-CommonLib.vcxproj" Id="1a066c63-64b3-45f8-92fe-664e1cce8077" />
<Project Path="src/common/updating/updating.vcxproj" Id="17da04df-e393-4397-9cf0-84dabe11032e" />
<Project Path="src/common/version/version.vcxproj" Id="cc6e41ac-8174-4e8a-8d22-85dd7f4851df" />
</Folder>
<Folder Name="/common/interop/">
<Project Path="src/common/interop/interop-tests/Common.Interop.UnitTests.csproj">
@@ -113,10 +116,8 @@
<File Path="src/common/utils/string_utils.h" />
<File Path="src/common/utils/timeutil.h" />
<File Path="src/common/utils/UnhandledExceptionHandler.h" />
<File Path="src/common/utils/version.h" />
<File Path="src/common/utils/winapi_error.h" />
<File Path="src/common/utils/window.h" />
<File Path="version.h" />
</Folder>
<Folder Name="/DSC/">
<Project Path="src/dsc/PowerToys.Settings.DSC.Schema.Generator/PowerToys.Settings.DSC.Schema.Generator.csproj">
@@ -142,6 +143,7 @@
<Platform Solution="*|x64" Project="x64" />
<Deploy />
</Project>
<Project Path="src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteModuleInterface.vcxproj" Id="fc373b24-3293-453c-aaf5-cf2909dcee6a" />
</Folder>
<Folder Name="/modules/AdvancedPaste/Tests/">
<Project Path="src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/AdvancedPaste.FuzzTests.csproj">
@@ -155,6 +157,7 @@
</Folder>
<Folder Name="/modules/AlwaysOnTop/">
<Project Path="src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.vcxproj" Id="1dc3be92-ce89-43fb-8110-9c043a2fe7a2" />
<Project Path="src/modules/alwaysontop/AlwaysOnTopModuleInterface/AlwaysOnTopModuleInterface.vcxproj" Id="48a0a19e-a0be-4256-acf8-cc3b80291af9" />
</Folder>
<Folder Name="/modules/awake/">
<Project Path="src/modules/awake/Awake.ModuleServices/Awake.ModuleServices.csproj">
@@ -165,12 +168,19 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/awake/AwakeModuleInterface/AwakeModuleInterface.vcxproj" Id="5e7360a8-d048-4ed3-8f09-0bfd64c5529a" />
</Folder>
<Folder Name="/modules/cmdNotFound/">
<Project Path="src/modules/cmdNotFound/CmdNotFoundModuleInterface/CmdNotFoundModuleInterface.vcxproj" Id="0014d652-901f-4456-8d65-06fc5f997fb0" />
</Folder>
<Folder Name="/modules/colorpicker/">
<Project Path="src/modules/colorPicker/ColorPicker.ModuleServices/ColorPicker.ModuleServices.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/colorPicker/ColorPicker/ColorPicker.vcxproj" Id="655c9af2-18d3-4da6-80e4-85504a7722ba">
<BuildDependency Project="src/common/logger/logger.vcxproj" />
</Project>
<Project Path="src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
@@ -184,6 +194,7 @@
</Folder>
<Folder Name="/modules/CommandPalette/">
<Project Path="src/modules/cmdpal/CmdPalKeyboardService/CmdPalKeyboardService.vcxproj" Id="5f63c743-f6ce-4dba-a200-2b3f8a14e8c2" />
<Project Path="src/modules/cmdpal/CmdPalModuleInterface/CmdPalModuleInterface.vcxproj" Id="0adeb797-c8c7-4ffa-acd5-2af6cad7ecd8" />
</Folder>
<Folder Name="/modules/CommandPalette/Built-in Extensions/">
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Microsoft.CmdPal.Ext.Apps.csproj">
@@ -289,6 +300,10 @@
</Project>
</Folder>
<Folder Name="/modules/CommandPalette/Tests/">
<Project Path="src/modules/cmdpal/Tests/Microsoft.CmdPal.Core.Common.UnitTests/Microsoft.CmdPal.Core.Common.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/cmdpal/Tests/Microsoft.CmdPal.Ext.Apps.UnitTests/Microsoft.CmdPal.Ext.Apps.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
@@ -345,6 +360,10 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/cmdpal/Tests/Microsoft.CommandPalette.Extensions.Toolkit.UnitTests/Microsoft.CommandPalette.Extensions.Toolkit.UnitTests.csproj" Id="2eca18b7-33b7-4829-88f1-439b20fd60f6">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/modules/CommandPalette/UI/">
<Project Path="src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Microsoft.CmdPal.UI.ViewModels.csproj">
@@ -360,12 +379,14 @@
</Folder>
<Folder Name="/modules/CropAndLock/">
<Project Path="src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj" Id="f5e1146e-b7b3-4e11-85fd-270a500bd78c" />
<Project Path="src/modules/CropAndLock/CropAndLockModuleInterface/CropAndLockModuleInterface.vcxproj" Id="3157fa75-86cf-4ee2-8f62-c43f776493c6" />
</Folder>
<Folder Name="/modules/EnvironmentVariables/">
<Project Path="src/modules/EnvironmentVariables/EnvironmentVariables/EnvironmentVariables.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/EnvironmentVariables/EnvironmentVariablesModuleInterface/EnvironmentVariablesModuleInterface.vcxproj" Id="b9420661-b0e4-4241-abd4-4a27a1f64250" />
<Project Path="src/modules/EnvironmentVariables/EnvironmentVariablesUILib/EnvironmentVariablesUILib.csproj" />
</Folder>
<Folder Name="/modules/fancyzones/">
@@ -383,6 +404,7 @@
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj" Id="f9c68edf-ac74-4b77-9af1-005d9c9f6a99" />
<Project Path="src/modules/fancyzones/FancyZonesModuleInterface/FancyZonesModuleInterface.vcxproj" Id="48804216-2a0e-4168-a6d8-9cd068d14227" />
</Folder>
<Folder Name="/modules/fancyzones/Tests/">
<Project Path="src/modules/fancyzones/FancyZones.FuzzTests/FancyZones.FuzzTests.csproj">
@@ -405,121 +427,8 @@
<BuildDependency Project="src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj" />
</Project>
</Folder>
<Folder Name="/modules/File Explorer/">
<Project Path="src/modules/previewpane/BgcodePreviewHandler/BgcodePreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/BgcodeThumbnailProvider/BgcodeThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/Common/PreviewHandlerCommon.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/FileExplorerDllExporter/FileExplorerDllExporter.vcxproj" Id="f6088a11-1c9e-4420-aa90-cf7e78dd7f1c" />
<Project Path="src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/QoiPreviewHandler/QoiPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/QoiThumbnailProvider/QoiThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/modules/File Explorer/Tests/">
<Project Path="src/modules/previewpane/UnitTests-BgcodePreviewHandler/Preview.BgcodePreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-BgcodeThumbnailProvider/Preview.BgcodeThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-GcodePreviewHandler/Preview.GcodePreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-GcodeThumbnailProvider/Preview.GcodeThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-MarkdownPreviewHandler/Preview.MarkdownPreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-PdfPreviewHandler/Preview.PdfPreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-PdfThumbnailProvider/Preview.PdfThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-PreviewHandlerCommon/Preview.PreviewHandlerCommon.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-QoiPreviewHandler/Preview.QoiPreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-QoiThumbnailProvider/Preview.QoiThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-StlThumbnailProvider/Preview.StlThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-SvgPreviewHandler/Preview.SvgPreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-SvgThumbnailProvider/Preview.SvgThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/modules/FileLocksmith/">
<Project Path="src/modules/FileLocksmith/FileLocksmithCLI/FileLocksmithCLI.vcxproj" Id="49d456d3-f485-45af-8875-45b44f193ddc" />
<Project Path="src/modules/FileLocksmith/FileLocksmithCLI/FileLocksmithCLI.vcxproj" Id="49D456D3-F485-45AF-8875-45B44F193DDC" />
<Project Path="src/modules/FileLocksmith/FileLocksmithContextMenu/FileLocksmithContextMenu.vcxproj" Id="799a50d8-de89-4ed1-8ff8-ad5a9ed8c0ca" />
<Project Path="src/modules/FileLocksmith/FileLocksmithExt/FileLocksmithExt.vcxproj" Id="57175ec7-92a5-4c1e-8244-e3fbca2a81de" />
<Project Path="src/modules/FileLocksmith/FileLocksmithLib/FileLocksmithLib.vcxproj" Id="9d52fd25-ef90-4f9a-a015-91efc5daf54f" />
@@ -530,13 +439,14 @@
</Project>
</Folder>
<Folder Name="/modules/FileLocksmith/Tests/">
<Project Path="src/modules/FileLocksmith/FileLocksmithCLI/tests/FileLocksmithCLIUnitTests.vcxproj" Id="a1b2c3d4-e5f6-7890-1234-567890abcdef" />
<Project Path="src/modules/FileLocksmith/FileLocksmithCLI/tests/FileLocksmithCLIUnitTests.vcxproj" Id="A1B2C3D4-E5F6-7890-1234-567890ABCDEF" />
</Folder>
<Folder Name="/modules/Hosts/">
<Project Path="src/modules/Hosts/Hosts/Hosts.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/Hosts/HostsModuleInterface/HostsModuleInterface.vcxproj" Id="b41b888c-7db8-4747-b262-4062e05a230d" />
<Project Path="src/modules/Hosts/HostsUILib/HostsUILib.csproj" />
</Folder>
<Folder Name="/modules/Hosts/Tests/">
@@ -555,16 +465,16 @@
</Folder>
<Folder Name="/modules/imageresizer/">
<Project Path="src/modules/imageresizer/dll/ImageResizerExt.vcxproj" Id="0b43679e-edfa-4da0-ad30-f4628b308b1b" />
<Project Path="src/modules/imageresizer/ImageResizerCLI/ImageResizerCLI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/imageresizer/ImageResizerContextMenu/ImageResizerContextMenu.vcxproj" Id="93b72a06-c8bd-484f-a6f7-c9f280b150bf" />
<Project Path="src/modules/imageresizer/ImageResizerLib/ImageResizerLib.vcxproj" Id="18b3db45-4ffe-4d01-97d6-5223feee1853" />
<Project Path="src/modules/imageresizer/ui/ImageResizerUI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/imageresizer/ImageResizerCLI/ImageResizerCLI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/modules/imageresizer/Tests/">
<Project Path="src/modules/imageresizer/tests/ImageResizer.UnitTests.csproj">
@@ -577,6 +487,7 @@
</Folder>
<Folder Name="/modules/keyboardmanager/">
<Project Path="src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj" Id="8affa899-0b73-49ec-8c50-0fadda57b2fc" />
<Project Path="src/modules/keyboardmanager/dll/KeyboardManager.vcxproj" Id="89f34af7-1c34-4a72-aa6e-534bcf972bd9" />
<Project Path="src/modules/keyboardmanager/KeyboardManagerEditor/KeyboardManagerEditor.vcxproj" Id="8df78b53-200e-451f-9328-01eb907193ae" />
<Project Path="src/modules/keyboardmanager/KeyboardManagerEditorLibrary/KeyboardManagerEditorLibrary.vcxproj" Id="23d2070d-e4ad-4add-85a7-083d9c76ad49" />
<Project Path="src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.vcxproj" Id="4382a954-179a-4078-92af-715187dfff50" />
@@ -592,6 +503,9 @@
<Project Path="src/modules/keyboardmanager/KeyboardManagerEngineTest/KeyboardManagerEngineTest.vcxproj" Id="7f4b3a60-bc27-45a7-8000-68b0b6ea7466" />
</Folder>
<Folder Name="/modules/launcher/">
<Project Path="src/modules/launcher/Microsoft.Launcher/Microsoft.Launcher.vcxproj" Id="e364f67b-bb12-4e91-b639-355866ebcd8b">
<BuildDependency Project="src/modules/launcher/PowerLauncher/PowerLauncher.csproj" />
</Project>
<Project Path="src/modules/launcher/PowerLauncher.Telemetry/PowerLauncher.Telemetry.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
@@ -759,6 +673,8 @@
</Project>
</Folder>
<Folder Name="/modules/LightSwitch/">
<Project Path="src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj" Id="79267138-2895-4346-9021-21408d65379f" />
<Project Path="src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj" Id="38177d56-6ad1-4adf-88c9-2843a7932166" />
<Project Path="src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj" Id="08e71c67-6a7e-4ca1-b04e-2fb336410bac" />
</Folder>
<Folder Name="/modules/LightSwitch/Tests/">
@@ -772,7 +688,9 @@
<Project Path="src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.vcxproj" Id="54a93af7-60c7-4f6c-99d2-fbb1f75f853a">
<BuildDependency Project="src/common/Display/Display.vcxproj" />
<BuildDependency Project="src/common/SettingsAPI/SettingsAPI.vcxproj" />
<BuildDependency Project="src/common/version/version.vcxproj" />
</Project>
<Project Path="src/modules/MeasureTool/MeasureToolModuleInterface/MeasureToolModuleInterface.vcxproj" Id="92c39820-9f84-4529-bc7d-22aae514d63b" />
<Project Path="src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
@@ -792,6 +710,7 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/MouseUtils/MouseJump/MouseJump.vcxproj" Id="8a08d663-4995-40e3-b42c-3f910625f284" />
<Project Path="src/modules/MouseUtils/MouseJumpUI/MouseJumpUI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
@@ -863,12 +782,14 @@
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/poweraccent/PowerAccentKeyboardService/PowerAccentKeyboardService.vcxproj" Id="c97d9a5d-206c-454e-997e-009e227d7f02" />
<Project Path="src/modules/poweraccent/PowerAccentModuleInterface/PowerAccentModuleInterface.vcxproj" Id="34a354c5-23c7-4343-916c-c52daf4fc39d" />
</Folder>
<Folder Name="/modules/PowerOCR/">
<Project Path="src/modules/PowerOCR/PowerOCR/PowerOCR.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/PowerOCR/PowerOCRModuleInterface/PowerOCRModuleInterface.vcxproj" Id="6ab6a2d6-f859-4a82-9184-0bd29c9f07d1" />
</Folder>
<Folder Name="/modules/PowerOCR/Tests/">
<Project Path="src/modules/PowerOCR/PowerOCR-UITests/PowerOCR.UITests.csproj">
@@ -898,11 +819,140 @@
<BuildDependency Project="src/modules/powerrename/lib/PowerRenameLib.vcxproj" />
</Project>
</Folder>
<Folder Name="/modules/previewpane/">
<Project Path="src/modules/previewpane/BgcodePreviewHandler/BgcodePreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/BgcodePreviewHandlerCpp/BgcodePreviewHandlerCpp.vcxproj" Id="f6088a11-1c9e-4420-aa90-cf7e78dd7f1c" />
<Project Path="src/modules/previewpane/BgcodeThumbnailProvider/BgcodeThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/BgcodeThumbnailProviderCpp/BgcodeThumbnailProviderCpp.vcxproj" Id="47b0678c-806b-4fe1-9f50-46ba88989532" />
<Project Path="src/modules/previewpane/Common/PreviewHandlerCommon.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/GcodePreviewHandler/GcodePreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandlerCpp.vcxproj" Id="5a5dd09d-723a-44d3-8f2b-293584c3d731" />
<Project Path="src/modules/previewpane/GcodeThumbnailProvider/GcodeThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/GcodeThumbnailProviderCpp/GcodeThumbnailProviderCpp.vcxproj" Id="56cc2f10-6e41-453d-be16-c593a5e58482" />
<Project Path="src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandlerCpp.vcxproj" Id="ed9a1ac6-aeb0-4569-a6e9-e1696182b545" />
<Project Path="src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandlerCpp.vcxproj" Id="b3e869c4-8210-4ebd-a621-ff4c4afcbfa9" />
<Project Path="src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandlerCpp.vcxproj" Id="54f7c616-fd41-4e62-bff9-015686914f4d" />
<Project Path="src/modules/previewpane/PdfThumbnailProvider/PdfThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/PdfThumbnailProviderCpp/PdfThumbnailProviderCpp.vcxproj" Id="ca5518ed-0458-4b09-8f53-4122b9888655" />
<Project Path="src/modules/previewpane/powerpreview/powerpreview.vcxproj" Id="217df501-135c-4e38-bfc8-99d4821032ea">
<BuildDependency Project="src/common/version/version.vcxproj" />
</Project>
<Project Path="src/modules/previewpane/QoiPreviewHandler/QoiPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/QoiPreviewHandlerCpp/QoiPreviewHandlerCpp.vcxproj" Id="3baf9c81-a194-4925-a035-5e24a5d1e542" />
<Project Path="src/modules/previewpane/QoiThumbnailProvider/QoiThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/QoiThumbnailProviderCpp/QoiThumbnailProviderCpp.vcxproj" Id="ccb5e44f-84d9-4203-83c6-1c9ec9302bc7" />
<Project Path="src/modules/previewpane/StlThumbnailProvider/StlThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/StlThumbnailProviderCpp/StlThumbnailProviderCpp.vcxproj" Id="d6dcc3ae-18c0-488a-b978-baa9e3cff09d" />
<Project Path="src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandlerCpp.vcxproj" Id="143f13e3-d2e3-4d83-b035-356612d99956" />
<Project Path="src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/SvgThumbnailProviderCpp/SvgThumbnailProviderCpp.vcxproj" Id="2bbc9e33-21ec-401c-84da-bb6590a9b2aa" />
</Folder>
<Folder Name="/modules/previewpane/Tests/">
<Project Path="src/modules/previewpane/UnitTests-BgcodePreviewHandler/Preview.BgcodePreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-BgcodeThumbnailProvider/Preview.BgcodeThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-GcodePreviewHandler/Preview.GcodePreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-GcodeThumbnailProvider/Preview.GcodeThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-MarkdownPreviewHandler/Preview.MarkdownPreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-PdfPreviewHandler/Preview.PdfPreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-PdfThumbnailProvider/Preview.PdfThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-PreviewHandlerCommon/Preview.PreviewHandlerCommon.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-QoiPreviewHandler/Preview.QoiPreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-QoiThumbnailProvider/Preview.QoiThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-StlThumbnailProvider/Preview.StlThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-SvgPreviewHandler/Preview.SvgPreviewHandler.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/previewpane/UnitTests-SvgThumbnailProvider/Preview.SvgThumbnailProvider.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/modules/RegistryPreview/">
<Project Path="src/modules/registrypreview/RegistryPreview/RegistryPreview.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/registrypreview/RegistryPreviewExt/RegistryPreviewExt.vcxproj" Id="697c6af9-0a48-49a9-866c-67da12384015" />
<Project Path="src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewUILib.csproj" />
</Folder>
<Folder Name="/modules/RegistryPreview/Test/">
@@ -934,6 +984,7 @@
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/Workspaces/WorkspacesLib/WorkspacesLib.vcxproj" Id="b31fcc55-b5a4-4ea7-b414-2dceae6af332" />
<Project Path="src/modules/Workspaces/WorkspacesModuleInterface/WorkspacesModuleInterface.vcxproj" Id="45285df2-9742-4eca-9ac9-58951fc26489" />
<Project Path="src/modules/Workspaces/WorkspacesSnapshotTool/WorkspacesSnapshotTool.vcxproj" Id="3d63307b-9d27-44fd-b033-b26f39245b85" />
<Project Path="src/modules/Workspaces/WorkspacesWindowArranger/WorkspacesWindowArranger.vcxproj" Id="37d07516-4185-43a4-924f-3c7a5d95ecf6" />
</Folder>
@@ -959,6 +1010,7 @@
</Folder>
<Folder Name="/modules/ZoomIt/">
<Project Path="src/modules/ZoomIt/ZoomIt/ZoomIt.vcxproj" Id="0a84f764-3a88-44cd-aa96-41bdbd48627b" />
<Project Path="src/modules/ZoomIt/ZoomItModuleInterface/ZoomItModuleInterface.vcxproj" Id="e4585179-2ac1-4d5f-a3ff-cfc5392f694c" />
<Project Path="src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettingsInterop.vcxproj" Id="ca7d8106-30b9-4aec-9d05-b69b31b8c461" />
</Folder>
<Folder Name="/settings-ui/">
@@ -1003,35 +1055,37 @@
<File Path="src/Solution.props" />
<File Path="src/Version.props" />
</Folder>
<Project Path="src/PackageIdentity/PackageIdentity.vcxproj" Id="e2a5a82e-1e5b-4c8d-9a4f-2b1a8f9e5c3d" />
<Project Path="src/PowerToys.ActionRunner/PowerToys.ActionRunner.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
<Project Path="src/ActionRunner/ActionRunner.vcxproj" Id="d29ddd63-e2cf-4657-9fd5-2aede4257e5d">
<BuildDependency Project="src/common/updating/updating.vcxproj" />
</Project>
<Project Path="src/PackageIdentity/PackageIdentity.vcxproj" Id="e2a5a82e-1e5b-4c8d-9a4f-2b1a8f9e5c3d" />
<Project Path="src/runner/runner.vcxproj" Id="9412d5c6-2cf2-4fc2-a601-b55508ea9b27">
<BuildDependency Project="src/ActionRunner/ActionRunner.vcxproj" />
<BuildDependency Project="src/common/notifications/BackgroundActivator/BackgroundActivator.vcxproj" />
<BuildDependency Project="src/common/notifications/BackgroundActivatorDLL/BackgroundActivatorDLL.vcxproj" />
<BuildDependency Project="src/common/updating/updating.vcxproj" />
<BuildDependency Project="src/modules/awake/Awake/Awake.csproj" />
<BuildDependency Project="src/modules/awake/AwakeModuleInterface/AwakeModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/colorPicker/ColorPicker/ColorPicker.vcxproj" />
<BuildDependency Project="src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj" />
<BuildDependency Project="src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj" />
<BuildDependency Project="src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj" />
<BuildDependency Project="src/modules/fancyzones/FancyZonesModuleInterface/FancyZonesModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/imageresizer/dll/ImageResizerExt.vcxproj" />
<BuildDependency Project="src/modules/imageresizer/ui/ImageResizerUI.csproj" />
<BuildDependency Project="src/modules/keyboardmanager/dll/KeyboardManager.vcxproj" />
<BuildDependency Project="src/modules/launcher/Microsoft.Launcher/Microsoft.Launcher.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj" />
<BuildDependency Project="src/modules/powerrename/dll/PowerRenameExt.vcxproj" />
<BuildDependency Project="src/modules/powerrename/lib/PowerRenameLib.vcxproj" />
<BuildDependency Project="src/modules/previewpane/Common/PreviewHandlerCommon.csproj" />
<BuildDependency Project="src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj" />
<BuildDependency Project="src/modules/previewpane/PdfPreviewHandler/PdfPreviewHandler.csproj" />
<BuildDependency Project="src/modules/previewpane/powerpreview/powerpreview.vcxproj" />
<BuildDependency Project="src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.csproj" />
<BuildDependency Project="src/PackageIdentity/PackageIdentity.vcxproj" />
</Project>
<Project Path="src/RunnerV2/RunnerV2/RunnerV2.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/Update/Update.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/Update/PowerToys.Update.vcxproj" Id="44ce9ae1-4390-42c5-bacc-0fd6b40aa203" />
<Project Path="tools/project_template/ModuleTemplate/ModuleTemplateCompileTest.vcxproj" Id="64a80062-4d8b-4229-8a38-dfa1d7497749" />
</Solution>

View File

@@ -51,19 +51,19 @@ But to get started quickly, choose one of the installation methods below:
Go to the <a href="https://aka.ms/installPowerToys">PowerToys GitHub releases</a>, click Assets to reveal the downloads, and choose the installer that matches your architecture and install scope. For most devices, that's the x64 per-user installer.
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.97%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.96%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.97.0/PowerToysUserSetup-0.97.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.97.0/PowerToysUserSetup-0.97.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.97.0/PowerToysSetup-0.97.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.97.0/PowerToysSetup-0.97.0-arm64.exe
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.98%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.97%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.97.1/PowerToysUserSetup-0.97.1-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.97.1/PowerToysUserSetup-0.97.1-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.97.1/PowerToysSetup-0.97.1-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.97.1/PowerToysSetup-0.97.1-arm64.exe
| Description | Filename |
|----------------|----------|
| Per user - x64 | [PowerToysUserSetup-0.97.0-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.97.0-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.97.0-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.97.0-arm64.exe][ptMachineArm64] |
| Per user - x64 | [PowerToysUserSetup-0.97.1-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.97.1-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.97.1-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.97.1-arm64.exe][ptMachineArm64] |
</details>
@@ -103,18 +103,38 @@ There are <a href="https://learn.microsoft.com/windows/powertoys/install#communi
</details>
## ✨ What's new
**Version 0.97 (January 2026)**
**Version 0.97.1 (January 2026)**
For an in-depth look at the latest changes, visit the [Windows Command Line blog](https://aka.ms/powertoys-releaseblog).
This patch release fixes several important stability issues identified in v0.97.0 based on incoming reports. Check out the [v0.97.0](https://github.com/microsoft/PowerToys/releases/tag/v0.97.0) notes for the full list of changes.
**Highlights**
- **Command Palette**: Major expansion with PowerToys extension (Windows 11 only), Remote Desktop built-in extension, theme customization, drag-and-drop support, fallback ranking controls, sections/separators for pages, pinyin Chinese matching, and many UX refinements.
- **Settings**: Quick Access flyout is now a standalone process for significantly faster startup, theme-adaptive tray icon, AOT serialization, and multiple UI/accessibility fixes
- **CursorWrap (New!)**: New mouse utility that lets your cursor wrap around screen edges, making multi-monitor navigation faster and more seamless.
- **Advanced Paste**: Image input for AI, color detection in clipboard history, Foundry Local improvements, Azure AI icons, and multiple bug fixes
- **CLI Support Expanded**: FancyZones, Image Resizer, and File Locksmith can now be controlled from the command line for layout management, batch image resizing, and file lock inspection.
- **LightSwitch**: Added support for automatically following Windows Night Light mode.
- **Release Experience & Quality**: Refreshed "Whats new" dialog, plus many performance improvements, stability fixes, and refinements across PowerToys.
**Highlights**
### Advanced Paste
- #44862: Fixed Settings UI advanced paste page crash by using correct settings repository for null checking.
### Command Palette
- #44886: Fixed personalization section not appearing by using latest MSIX for installation.
- #44938: Fixed loading of icons from internet shortcuts. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- #45076: Fixed potential deadlock from lazy-loading AppListItem details. Thanks [@jiripolasek](https://github.com/jiripolasek)!
### Cursor Wrap
- #44936: Added improved multi-monitor support; Added laptop lid close detection for dynamic monitor topology updates. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
- #44936: Added new settings dropdown to constrain wrapping to horizontal-only, vertical-only, or both directions. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
### Peek
- #44995: Fixed Space key triggering Peek during file rename, search, or address bar typing.
### PowerRename
- #44944: Fixed regex `$` not working, preventing users from adding text at the end of filenames.
### Runner
- #44931: Monochrome tray icon now adapts to Windows system theme instead of app theme.
- #44982: Fixed right-click menu to dynamically update based on Quick Access enabled/disabled state.
### GPO / Enterprise
- #45028: Added CursorWrap policy definition to ADMX templates. Thanks [@htcfreek](https://github.com/htcfreek)!
For the full list of v0.97 changes, visit the [Windows Command Line blog](https://aka.ms/powertoys-releaseblog).
## Advanced Paste
@@ -289,7 +309,7 @@ For an in-depth look at the latest changes, visit the [Windows Command Line blog
- Stabilized FancyZones UI tests with more reliable selectors and screen recordings.
## 🛣️ Roadmap
We are planning some nice new features and improvements for the next releases PowerDisplay, Command Palette improvements and a brand-new Shortcut Guide experience! Stay tuned for [v0.97][github-next-release-work]!
We are planning some nice new features and improvements for the next releases PowerDisplay, Command Palette improvements and a brand-new Shortcut Guide experience! Stay tuned for [v0.98][github-next-release-work]!
## ❤️ PowerToys Community
The PowerToys team is extremely grateful to have the [support of an amazing active community][community-link]. The work you do is incredibly important. PowerToys wouldn't be nearly what it is today without your help filing bugs, updating documentation, guiding the design, or writing features. We want to say thank you and take time to recognize your work. Your contributions and feedback improve PowerToys month after month!

View File

@@ -88,7 +88,7 @@
### Building PowerToys Locally
#### One stop script for building installer
1. Open developer powershell for vs 2022
1. Open `Developer Powershell for VS 2022` or `Developer PowerShell for VS` for VS 2026.
2. Run tools\build\build-installer.ps1
> For the first-time setup, please run the installer as an administrator. This ensures that the Wix tool can move wix.target to the desired location and trust the certificate used to sign the MSIX packages.
@@ -109,7 +109,7 @@ dotnet tool install --global wix --version 5.0.2
##### From the command line
1. From the start menu, open a `Developer Command Prompt for VS 2022`
1. From the start menu, open a `Developer Command Prompt for VS 2022` or `Developer Command Prompt for VS`
1. Ensure `nuget.exe` is in your `%path%`
1. In the repo root, run these commands:
@@ -140,7 +140,7 @@ If you prefer, you can alternatively build prerequisite projects for the install
The resulting installer will be available in the `installer\PowerToysSetupVNext\x64\Release\` folder.
To build the installer from the command line, run `Developer Command Prompt for VS 2022` in admin mode and execute the following commands. The generated installer package will be located at `\installer\PowerToysSetupVNext\{platform}\Release\MachineSetup`.
To build the installer from the command line, run `Developer Command Prompt for VS 2022` or `Developer Command Prompt for VS` in admin mode and execute the following commands. The generated installer package will be located at `\installer\PowerToysSetupVNext\{platform}\Release\MachineSetup`.
```
git clean -xfd -e *exe -- .\installer\

View File

@@ -15,7 +15,7 @@ Before you can start debugging PowerToys, you need to set up your development en
You can build the entire solution from the command line, which is sometimes faster than building within Visual Studio:
1. Open Developer Command Prompt for VS 2022
1. Open `Developer Command Prompt for VS 2022` or `Developer Command Prompt for VS`
2. Navigate to the repository root directory
3. Run the following command(don't forget to set the correct platform):
```pwsh
@@ -105,7 +105,7 @@ If you encounter build errors about missing image files (e.g., `.png`, `.ico`, o
1. **Clean the solution in Visual Studio**: Build > Clean Solution
Or from the command line (Developer Command Prompt for VS 2022):
Or from the command line (Developer Command Prompt for VS 2022 or Developer Command Prompt for VS):
```pwsh
msbuild PowerToys.slnx /t:Clean /p:Platform=x64 /p:Configuration=Debug
```

View File

@@ -15,9 +15,11 @@ VS Code extensions Needed:
---
## Building in VS Code
### Configure developer powershell for vs2022 for more convenient dev in vscode.
### Configure Developer Powershell for VS 2022 or Developer Powershell for VS for more convenient dev in vscode.
1. Configure profile in in settings, entry: "terminal.integrated.profiles.windows"
2. Add below config as entry:
2. Add below config as entry (choose VS 2022 or VS 2026 based on your installation):
**For Visual Studio 2022:**
```json
"Developer PowerShell for VS 2022": {
// Configure based on your preference
@@ -27,16 +29,35 @@ VS Code extensions Needed:
"-Command",
"& {",
"$orig = Get-Location;",
// Configure based on your environment
// Adjust path based on your edition (Community/Professional/Enterprise)
"& 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1';",
"Set-Location $orig",
"}"
]
},
```
3. [Optional] Set Developer PowerShell for VS 2022 as your default profile, so that you can get a deep integration with vscode coding agent.
4. Now You can build with plain `msbuild` or configure tasks.json in below section
**For Visual Studio 2026:**
```json
"Developer PowerShell for VS": {
// Configure based on your preference
"path": "C:\\Program Files\\WindowsApps\\Microsoft.PowerShell_7.5.2.0_arm64__8wekyb3d8bbwe\\pwsh.exe",
"args": [
"-NoExit",
"-Command",
"& {",
"$orig = Get-Location;",
// Adjust path based on your edition (Community/Professional/Enterprise)
"& 'C:\\Program Files\\Microsoft Visual Studio\\18\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1';",
"Set-Location $orig",
"}"
]
},
```
3. [Optional] Set your Developer PowerShell profile as the default, so that you can get a deep integration with vscode coding agent.
4. Now you can build with plain `msbuild` or configure tasks.json in below section.
Or reach out to "tools\build\BUILD-GUIDELINES.md"
### Sample plain msbuild command

View File

@@ -152,7 +152,7 @@ FancyZones is divided into several projects:
## Development Environment Setup
### Prerequisites
- Visual Studio 2022: Required for building and debugging
- Visual Studio 2022 or 2026: Required for building and debugging
- Windows 10 SDK: Ensure the latest version is installed
- PowerToys Repository: Clone from GitHub
@@ -183,7 +183,7 @@ FancyZones is divided into several projects:
## Debugging
### Setup for Debugging
1. In Visual Studio 2022, set FancyZonesEditor as the startup project
1. In Visual Studio 2022 or 2026, set FancyZonesEditor as the startup project
2. Set breakpoints in the code where needed
3. Click Run to start debugging

View File

@@ -79,7 +79,7 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and an
### Prerequisites for Compiling PowerToys
1. Windows 10 April 2018 Update (version 1803) or newer
1. Visual Studio Community/Professional/Enterprise 2022 17.4 or newer
1. Visual Studio Community/Professional/Enterprise 2022 17.4 or newer, or Visual Studio 2026
1. A local clone of the PowerToys repository
1. Enable long paths in Windows (see [Enable Long Paths](https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation#enabling-long-paths-in-windows-10-version-1607-and-later) for details)

View File

@@ -610,6 +610,13 @@ UINT __stdcall InstallPackageIdentityMSIXCA(MSIHANDLE hInstall)
hr = WcaInitialize(hInstall, "InstallPackageIdentityMSIXCA");
ExitOnFailure(hr, "Failed to initialize");
// Double-check: Only install on Windows 11 or greater
if (!package::IsWin11OrGreater())
{
Logger::info(L"Skipping PackageIdentity MSIX installation - not Windows 11 or greater");
goto LExit;
}
hr = WcaGetProperty(L"CustomActionData", &customActionData);
ExitOnFailure(hr, "Failed to get CustomActionData property");

View File

@@ -14,13 +14,13 @@
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="..\..\deps\spdlog.props" />

View File

@@ -2,7 +2,7 @@
//
#include <windows.h>
#include "resource.h"
#include "../../src/common/utils/version.h"
#include "../../src/common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////

View File

@@ -18,6 +18,7 @@
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFile Id="RemoveOldCmdPalMsix" Name="Microsoft.CmdPal.UI_*.msix" On="install" />
<?if $(sys.BUILDARCH) = x64 ?>
<File Id="Microsoft.CmdPal.UI___var.CmdPalVersion_._x64.msix" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_x64.msix" />
<?else?>

View File

@@ -1,5 +1,5 @@
<Project>
<Import Project="..\..\src\Version.props" Condition="Exists('..\..\src\Version.props')" />
<Import Project="..\..\Directory.Build.props" />
<PropertyGroup>
<!-- Set BaseIntermediateOutputPath for each project to avoid conflicts -->
<BaseIntermediateOutputPath Condition="'$(MSBuildProjectName)' == 'PowerToysInstallerVNext'">obj\Installer\</BaseIntermediateOutputPath>

View File

@@ -124,7 +124,7 @@
<Custom Action="SetBundleInstallLocation" After="InstallFiles" Condition="NOT Installed OR WIX_UPGRADE_DETECTED" />
<Custom Action="ApplyModulesRegistryChangeSets" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="InstallCmdPalPackage" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="InstallPackageIdentityMSIX" After="InstallFiles" Condition="NOT Installed AND WINDOWSBUILDNUMBER &gt;= 22000" />
<Custom Action="InstallPackageIdentityMSIX" After="InstallFiles" Condition="(NOT Installed) AND (WINDOWSBUILDNUMBER &gt;= 22000)" />
<Custom Action="override Wix4CloseApplications_$(sys.BUILDARCHSHORT)" Before="RemoveFiles" />
<Custom Action="RemovePowerToysSchTasks" After="RemoveFiles" />
<!-- TODO: Use to activate embedded MSIX -->

View File

@@ -37,14 +37,14 @@
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
@@ -68,11 +68,10 @@
<ClCompile Include="SilentFilesInUseBAFunctions.cpp" />
<ClCompile Include="bafunctions.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="precomp.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,6 +1,6 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
#include "precomp.h"
#include "pch.h"
#include "BalBaseBAFunctions.h"
#include "BalBaseBAFunctionsProc.h"
@@ -18,7 +18,6 @@ public: // IBootstrapperApplication
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "*** CUSTOM BA FUNCTION SYSTEM ACTIVE *** Running detect begin BA function. fCached=%d, registrationType=%d, cPackages=%u, fCancel=%d", fCached, registrationType, cPackages, *pfCancel);
LExit:
return hr;
}
@@ -37,7 +36,6 @@ public: // IBAFunctions
// BalExitOnFailure(hr, "Change this message to represent real error handling.");
//-------------------------------------------------------------------------------------------------
LExit:
return hr;
}
@@ -58,7 +56,7 @@ public: // IBAFunctions
__in DWORD cFiles,
__in_ecount_z(cFiles) LPCWSTR* rgwzFiles,
__in int nRecommendation,
__in BOOTSTRAPPER_FILES_IN_USE_TYPE source,
__in BOOTSTRAPPER_FILES_IN_USE_TYPE /* source */,
__inout int* pResult
)
{

View File

@@ -1,6 +1,6 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
#include "precomp.h"
#include "pch.h"
static HINSTANCE vhInstance = NULL;

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="DOTNET_CORE_DOWNLOAD_FAILURE" xml:space="preserve">
<value>Couldn't download .NET Core Desktop Runtime 3.1, please install it manually.</value>
</data>
<data name="DOTNET_CORE_DOWNLOAD_FAILURE_TITLE" xml:space="preserve">
<value>PowerToys installation error</value>
</data>
<data name="GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT" xml:space="preserve">
<value>An update to PowerToys is available. Visit our GitHub page to update.</value>
</data>
</root>

View File

@@ -0,0 +1,36 @@
#include <windows.h>
#include "resource.h"
#include "../common/version/version.h"
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
END
END

View File

@@ -0,0 +1,109 @@
// 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.
#define WIN32_LEAN_AND_MEAN
#include "Generated Files/resource.h"
#include <Windows.h>
#include <shellapi.h>
#include <filesystem>
#include <string_view>
#include <common/utils/elevation.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include <common/utils/timeutil.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/logger/logger.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Storage.h>
#include "../runner/tray_icon.h"
#include "../runner/ActionRunnerUtils.h"
using namespace cmdArg;
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
int nArgs = 0;
LPWSTR* args = CommandLineToArgvW(GetCommandLineW(), &nArgs);
if (!args || nArgs < 2)
{
return 1;
}
std::wstring_view action{ args[1] };
std::filesystem::path logFilePath(PTSettingsHelper::get_root_save_folder_location());
logFilePath.append(LogSettings::actionRunnerLogPath);
Logger::init(LogSettings::actionRunnerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
if (action == RUN_NONELEVATED)
{
int nextArg = 2;
std::wstring_view target;
std::wstring_view pidFile;
std::wstring params;
while (nextArg < nArgs)
{
if (std::wstring_view(args[nextArg]) == L"-target" && nextArg + 1 < nArgs)
{
target = args[nextArg + 1];
nextArg += 2;
}
else if (std::wstring_view(args[nextArg]) == L"-pidFile" && nextArg + 1 < nArgs)
{
pidFile = args[nextArg + 1];
nextArg += 2;
}
else
{
params += args[nextArg];
params += L' ';
nextArg++;
}
}
HANDLE hMapFile = NULL;
PDWORD pidBuffer = NULL;
if (!pidFile.empty())
{
hMapFile = OpenFileMappingW(FILE_MAP_WRITE, FALSE, pidFile.data());
if (hMapFile)
{
pidBuffer = static_cast<PDWORD>(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(DWORD)));
if (pidBuffer)
{
*pidBuffer = 0;
}
}
}
run_same_elevation(target.data(), params, pidBuffer);
if (!pidFile.empty())
{
if (pidBuffer)
{
FlushViewOfFile(pidBuffer, sizeof(DWORD));
UnmapViewOfFile(pidBuffer);
}
if (hMapFile)
{
FlushFileBuffers(hMapFile);
CloseHandle(hMapFile);
}
}
}
return 0;
}

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h actionRunner.base.rc actionRunner.rc" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}</ProjectGuid>
<RootNamespace>actionRunner</RootNamespace>
<ProjectName>PowerToys.ActionRunner</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
</PropertyGroup>
<Import Project="..\..\deps\expected.props" />
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup>
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ActionRunner.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<None Include="ActionRunner.base.rc" />
<ResourceCompile Include="Generated Files\ActionRunner.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,11 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by PowerToys.ActionRunner.rc
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "PowerToys ActionRunner"
#define INTERNAL_NAME "PowerToys.ActionRunner"
#define ORIGINAL_FILENAME "PowerToys.ActionRunner.exe"

View File

@@ -5,6 +5,6 @@
As a temporary workaround, create a .NET 8 project and use file links
to include the code that needs testing. -->
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<TargetFramework>net8.0-windows10.0.26100.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@@ -55,26 +55,26 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>

View File

@@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>

View File

@@ -1,119 +0,0 @@
// 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.Diagnostics;
using System.Runtime.InteropServices;
namespace PowerToys.ActionRunner;
internal sealed partial class Program
{
private static void Main(string[] args)
{
if (args.Length < 1)
{
Environment.Exit(1);
return;
}
switch (args[0])
{
case "-run-non-elevated":
ExecuteRunNonElevated(args[1..]);
break;
default:
Environment.Exit(1);
break;
}
}
private static void ExecuteRunNonElevated(string[] args)
{
string? target = null;
string? pidFile = null;
string? arguments = null;
for (int i = 0; i < args.Length; i++)
{
string arg = args[i];
if (arg == "-target" && i + 1 < args.Length)
{
target = args[i + 1];
i++;
continue;
}
else if (arg == "-pidFile" && i + 1 < args.Length)
{
pidFile = args[i + 1];
i++;
continue;
}
arguments = args[i + 1] + " ";
i++;
if (target == null)
{
Environment.Exit(1);
return;
}
if (!string.IsNullOrEmpty(pidFile))
{
IntPtr pidBuffer = IntPtr.Zero;
IntPtr mapFile = OpenFileMapping(0x0002 /* FILE_MAP_WRITE */, false, pidFile);
if (mapFile != IntPtr.Zero)
{
pidBuffer = MapViewOfFile(mapFile, 0x001F /* FILE_MAP_ALL_ACCESS */, 0, 0, sizeof(uint));
if (pidBuffer != IntPtr.Zero)
{
Marshal.WriteInt32(pidBuffer, 0);
}
}
Process? p = Process.Start(new ProcessStartInfo
{
FileName = target,
Arguments = arguments.Trim(),
UseShellExecute = true,
});
if (pidBuffer != IntPtr.Zero)
{
Marshal.WriteInt32(pidBuffer, p?.Id ?? 0);
FlushViewOfFile(pidBuffer, sizeof(uint));
UnmapViewOfFile(pidBuffer);
}
if (mapFile != IntPtr.Zero)
{
FlushFileBuffers(mapFile);
CloseHandle(mapFile);
}
}
}
}
[LibraryImport("Kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
private static partial IntPtr OpenFileMapping(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, string lpName);
[LibraryImport("Kernel32.dll", SetLastError = true)]
private static partial IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap);
[LibraryImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool UnmapViewOfFile(IntPtr lpBaseAddress);
[LibraryImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool FlushViewOfFile(IntPtr lpBaseAddress, uint dwNumberOfBytesToFlush);
[LibraryImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool FlushFileBuffers(IntPtr hFile);
[LibraryImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool CloseHandle(IntPtr hObject);
}

View File

@@ -1,17 +0,0 @@
// 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 Windows.ApplicationModel;
namespace RunnerV2.Extensions
{
internal static class PackageVersionExtensions
{
public static Version ToVersion(this PackageVersion packageVersion)
{
return new Version(packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision);
}
}
}

View File

@@ -1,57 +0,0 @@
// 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.Runtime.InteropServices;
namespace RunnerV2.Helpers
{
internal static class COMUtils
{
public static void InitializeCOMSecurity(string securityDescriptor)
{
if (!NativeMethods.ConvertStringSecurityDescriptorToSecurityDescriptorW(
securityDescriptor,
1,
out IntPtr pSD,
out _))
{
return;
}
uint absoluteSDSize = 0;
uint daclSize = 0;
uint groupSize = 0;
uint ownerSize = 0;
uint saclSize = 0;
if (!NativeMethods.MakeAbsoluteSD(pSD, IntPtr.Zero, ref absoluteSDSize, IntPtr.Zero, ref daclSize, IntPtr.Zero, ref saclSize, IntPtr.Zero, ref ownerSize, IntPtr.Zero, ref groupSize))
{
return;
}
IntPtr absoluteSD = Marshal.AllocHGlobal((int)absoluteSDSize);
IntPtr dacl = Marshal.AllocHGlobal((int)daclSize);
IntPtr sacl = Marshal.AllocHGlobal((int)saclSize);
IntPtr owner = Marshal.AllocHGlobal((int)ownerSize);
IntPtr group = Marshal.AllocHGlobal((int)groupSize);
if (!NativeMethods.MakeAbsoluteSD(pSD, absoluteSD, ref absoluteSDSize, dacl, ref daclSize, sacl, ref saclSize, owner, ref ownerSize, group, ref groupSize))
{
return;
}
_ = NativeMethods.CoInitializeSecurity(
absoluteSD,
-1,
IntPtr.Zero,
IntPtr.Zero,
6, // RPC_C_AUTHN_LEVEL_PKT_PRIVACY
2, // RPC_C_IMP_LEVEL_IDENTIFY
IntPtr.Zero,
64 | 4096, // EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA
IntPtr.Zero);
}
}
}

View File

@@ -1,218 +0,0 @@
// 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 ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Windows.System;
namespace RunnerV2.Helpers
{
internal static class CentralizedKeyboardHookManager
{
private static readonly UIntPtr _ignoreKeyEventFlag = 0x5555;
private static readonly Dictionary<string, List<(HotkeySettings HotkeySettings, Action Action)>> _keyboardHooks = [];
private static HotkeySettingsControlHook _hotkeySettingsControlHook = new(OnKeyDown, OnKeyUp, IsActive, (_, specialFlags) => specialFlags != _ignoreKeyEventFlag);
private static void OnKeyDown(int key)
{
if ((VirtualKey)key == VirtualKey.RightMenu && _ctrlState)
{
_ctrlAltState = true;
}
switch ((VirtualKey)key)
{
case VirtualKey.Control:
case VirtualKey.LeftControl:
case VirtualKey.RightControl:
_ctrlState = true;
break;
case VirtualKey.Menu:
case VirtualKey.LeftMenu:
case VirtualKey.RightMenu:
_altState = true;
break;
case VirtualKey.Shift:
case VirtualKey.LeftShift:
case VirtualKey.RightShift:
_shiftState = true;
break;
case VirtualKey.LeftWindows:
case VirtualKey.RightWindows:
_winState = true;
break;
default:
if (OnKeyboardEvent(new HotkeySettings
{
Code = key,
Ctrl = _ctrlState,
Alt = _altState,
Shift = _shiftState,
Win = _winState,
}))
{
return;
}
break;
}
SendSingleKeyboardInput((short)key, (uint)NativeKeyboardHelper.KeyEventF.KeyDown);
}
private static void OnKeyUp(int key)
{
switch ((VirtualKey)key)
{
case VirtualKey.Control:
case VirtualKey.LeftControl:
case VirtualKey.RightControl:
_ctrlState = false;
break;
case VirtualKey.Menu:
case VirtualKey.LeftMenu:
case VirtualKey.RightMenu:
_altState = false;
break;
case VirtualKey.Shift:
case VirtualKey.LeftShift:
case VirtualKey.RightShift:
_shiftState = false;
break;
case VirtualKey.LeftWindows:
case VirtualKey.RightWindows:
_winState = false;
break;
}
// Correctly release Ctrl key if Ctrl+Alt (AltGr) was used.
if (_ctrlAltState && (VirtualKey)key == VirtualKey.RightMenu)
{
_ctrlAltState = false;
_ctrlState = false;
SendSingleKeyboardInput((short)VirtualKey.LeftControl, (uint)NativeKeyboardHelper.KeyEventF.KeyUp);
}
SendSingleKeyboardInput((short)key, (uint)NativeKeyboardHelper.KeyEventF.KeyUp);
}
private static bool _ctrlState;
private static bool _altState;
private static bool _shiftState;
private static bool _winState;
private static bool _ctrlAltState;
private static bool _isActive;
private static bool IsActive()
{
return _isActive;
}
public static void AddKeyboardHook(string moduleName, HotkeySettings hotkeySettings, Action action)
{
#pragma warning disable CA1854 // Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method
if (!_keyboardHooks.ContainsKey(moduleName))
{
_keyboardHooks[moduleName] = [];
}
#pragma warning restore CA1854 // Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method
_keyboardHooks[moduleName].Add((hotkeySettings, action));
}
public static void RemoveAllHooksFromModule(string moduleName)
{
_keyboardHooks.Remove(moduleName);
}
private static bool OnKeyboardEvent(HotkeySettings pressedHotkey)
{
bool shortcutHandled = false;
foreach (var moduleHooks in _keyboardHooks.Values)
{
foreach (var (hotkeySettings, action) in moduleHooks)
{
if (hotkeySettings == pressedHotkey)
{
action();
shortcutHandled = true;
}
}
}
return shortcutHandled;
}
public static void Start()
{
if (_hotkeySettingsControlHook.GetDisposedState())
{
_hotkeySettingsControlHook = new(OnKeyDown, OnKeyUp, IsActive, (_, specialFlags) => specialFlags != _ignoreKeyEventFlag);
}
_isActive = true;
}
public static void Stop()
{
_isActive = false;
_hotkeySettingsControlHook.Dispose();
}
// Function to send a single key event to the system which would be ignored by the hotkey control.
private static void SendSingleKeyboardInput(short keyCode, uint keyStatus)
{
if (IsExtendedVirtualKey(keyCode))
{
keyStatus |= (uint)NativeKeyboardHelper.KeyEventF.ExtendedKey;
}
NativeKeyboardHelper.INPUT input = new()
{
type = NativeKeyboardHelper.INPUTTYPE.INPUT_KEYBOARD,
data = new NativeKeyboardHelper.InputUnion
{
ki = new NativeKeyboardHelper.KEYBDINPUT
{
wVk = keyCode,
dwFlags = keyStatus,
dwExtraInfo = _ignoreKeyEventFlag,
},
},
};
NativeKeyboardHelper.INPUT[] inputs = [input];
_ = NativeMethods.SendInput(1, inputs, NativeKeyboardHelper.INPUT.Size);
}
private static bool IsExtendedVirtualKey(short vk)
{
return vk switch
{
0xA5 => true, // VK_RMENU (Right Alt - AltGr)
0xA3 => true, // VK_RCONTROL
0x2D => true, // VK_INSERT
0x2E => true, // VK_DELETE
0x23 => true, // VK_END
0x24 => true, // VK_HOME
0x21 => true, // VK_PRIOR (Page Up)
0x22 => true, // VK_NEXT (Page Down)
0x25 => true, // VK_LEFT
0x26 => true, // VK_UP
0x27 => true, // VK_RIGHT
0x28 => true, // VK_DOWN
0x90 => true, // VK_NUMLOCK
_ => false,
};
}
}
}

View File

@@ -1,90 +0,0 @@
// 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.Diagnostics;
using System.Runtime.InteropServices;
using static RunnerV2.NativeMethods;
namespace RunnerV2.Helpers
{
internal static partial class ElevationHelper
{
internal static RestartScheduledMode RestartScheduled { get; set; } = RestartScheduledMode.None;
internal enum RestartScheduledMode
{
None,
RestartElevated,
RestartElevatedWithOpenSettings,
RestartNonElevated,
}
private static bool? _cachedValue;
internal static void RestartIfScheudled()
{
switch (RestartScheduled)
{
case RestartScheduledMode.None:
return;
case RestartScheduledMode.RestartElevated:
RestartAsAdministrator("--restartedElevated");
break;
case RestartScheduledMode.RestartElevatedWithOpenSettings:
RestartAsAdministrator("--restartedElevated --open-settings");
break;
case RestartScheduledMode.RestartNonElevated:
// Todo: restart unelevated
break;
}
}
private static void RestartAsAdministrator(string arguments)
{
ProcessStartInfo processStartInfo = new()
{
Arguments = arguments,
Verb = "runas",
UseShellExecute = true,
FileName = Environment.ProcessPath,
};
try
{
Process.Start(processStartInfo);
}
catch (Exception ex)
{
Console.WriteLine("Failed to restart as administrator: " + ex);
}
}
internal static bool IsProcessElevated(bool useCachedValue = true)
{
if (_cachedValue is not null && useCachedValue)
{
return _cachedValue.Value;
}
bool elevated = false;
if (OpenProcessToken(Process.GetCurrentProcess().Handle, TOKENQUERY, out nint token))
{
TokenElevation elevation = default;
if (GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TOKEN_ELEVATION, ref elevation, (uint)Marshal.SizeOf(elevation), out uint _))
{
elevated = elevation.TokenIsElevated != 0;
}
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
}
_cachedValue = elevated;
return elevated;
}
}
}

View File

@@ -1,52 +0,0 @@
// 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.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.Win32;
namespace RunnerV2.Helpers
{
internal static class NotificationHelper
{
public enum ToastType
{
ElevatedDontShowAgain,
CouldntToggleFileExplorerModules,
}
public static string GetToastKey(ToastType key) => key switch
{
ToastType.ElevatedDontShowAgain => @"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain\{e16ea82f-6d94-4f30-bb02-d6d911588afd}",
ToastType.CouldntToggleFileExplorerModules => @"(SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain\{7e29e2b2-b31c-4dcd-b7b0-79c078b02430})",
_ => throw new ArgumentOutOfRangeException(nameof(key), key, null),
};
public static bool DisableToast(ToastType type)
{
try
{
RegistryKey? key = Registry.CurrentUser.CreateSubKey(GetToastKey(type));
if (key != null)
{
key.SetValue(null, BitConverter.GetBytes(DateTimeOffset.UtcNow.ToUnixTimeSeconds()), RegistryValueKind.QWord);
key.Close();
return true;
}
}
catch (Exception e)
{
Logger.LogError("Could not disable toast notification.", e);
}
return false;
}
}
}

View File

@@ -1,179 +0,0 @@
// 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.Reflection;
using System.Text.RegularExpressions;
using ManagedCommon;
using RunnerV2.Extensions;
using Windows.ApplicationModel;
using Windows.Foundation;
using Windows.Management.Deployment;
namespace RunnerV2.Helpers
{
/// <summary>
/// Provides helper methods for working with UWP packages.
/// </summary>
internal static partial class PackageHelper
{
/// <summary>
/// Gets the registered UWP package based on the display name and version check.
/// </summary>
/// <param name="packageDisplayName">The display name of the package.</param>
/// <param name="checkVersion">If true, the package version will be checked against the executing assembly version.</param>
/// <returns>If a package is found the corresponding <see cref="Package"/> object. If none is found <c>null</c>.</returns>
internal static Package? GetRegisteredPackage(string packageDisplayName, bool checkVersion)
{
PackageManager packageManager = new();
foreach (var package in packageManager.FindPackagesForUser(null))
{
if (package.Id.FullName.Contains(packageDisplayName) && (!checkVersion || package.Id.Version.ToVersion() == Assembly.GetExecutingAssembly().GetName().Version))
{
return package;
}
}
return null;
}
internal static string[] FindMsixFiles(string directoryPath, bool recursive)
{
if (!Directory.Exists(directoryPath))
{
Logger.LogError("Tried to search msix files in " + directoryPath + ", but it does not exist.");
return [];
}
List<string> matchedFiles = [];
try
{
foreach (string file in Directory.GetFiles(directoryPath, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
{
if (File.Exists(file) && msixPackagePattern().IsMatch(Path.GetFileName(file)))
{
matchedFiles.Add(file);
}
}
}
catch (Exception e)
{
Logger.LogError("An error occured while searching for MSIX files.", e);
}
return [.. matchedFiles];
}
/// <summary>
/// Installs the specified appx package along with its dependencies.
/// </summary>
/// <param name="packagePath">Path to the package</param>
/// <param name="dependencies">Array of dependency package paths</param>
/// <returns>True if the installation was successful, false otherwise</returns>
internal static bool InstallPackage(string packagePath, string[] dependencies)
{
Logger.LogInfo("Starting package install of package \"" + packagePath + "\"");
PackageManager packageManager = new();
List<Uri> uris = [];
foreach (string dependency in dependencies)
{
try
{
if (IsPackageSatisfied(dependency))
{
Logger.LogInfo("Dependency \"" + dependency + "\" is already satisfied.");
continue;
}
else
{
uris.Add(new Uri(packagePath));
}
}
catch (Exception ex)
{
Logger.LogError("Could not process dependency package at path \"" + dependency + "\"", ex);
}
}
try
{
IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> deploymentOperation = packageManager.AddPackageAsync(new Uri(packagePath), uris, DeploymentOptions.ForceApplicationShutdown);
deploymentOperation.Get();
switch (deploymentOperation.Status)
{
case AsyncStatus.Error:
Logger.LogError($"Registering {packagePath} failed. ErrorCode: {deploymentOperation.ErrorCode}, ErrorText: {deploymentOperation.GetResults().ErrorText}");
break;
case AsyncStatus.Canceled:
Logger.LogError($"Registering {packagePath} was canceled.");
break;
case AsyncStatus.Completed:
Logger.LogInfo($"Registering {packagePath} succeded.");
break;
default:
Logger.LogDebug($"Registering {packagePath} package started.");
break;
}
return true;
}
catch (Exception e)
{
Logger.LogError($"Exception thrown while trying to register package: {packagePath}", e);
}
return false;
}
/// <summary>
/// Checks if the package specified by the given path is already installed and satisfies the required version.
/// </summary>
/// <param name="packagePath">Path to the package.</param>
/// <returns>True if the package is already installed and satisfies the required version, false otherwise.</returns>
private static bool IsPackageSatisfied(string packagePath)
{
if (!GetPackageNameAndVersionFromAppx(packagePath, out string name, out PackageVersion version))
{
Logger.LogError("Could not get package name and version from dependency package at path \"" + packagePath + "\"");
return false;
}
PackageManager packageManager = new();
foreach (var package in packageManager.FindPackagesForUser(null))
{
if (package.Id.Name.Equals(name, StringComparison.OrdinalIgnoreCase) &&
package.Id.Version.ToVersion() > version.ToVersion())
{
Logger.LogInfo($@"Package ""{name}"" is already statisfied with version: {package.Id.Version}. Target version: {version}. PackagePath: {packagePath}");
return true;
}
}
Logger.LogInfo($@"Package ""{name}"" with version {version} is not satisfied. PackagePath: {packagePath}");
return false;
}
/// <summary>
/// Gets the package name and version from the specified appx package file.
/// </summary>
/// <param name="packagePath">Path to the package file.</param>
/// <param name="name">Output parameter for the package name.</param>
/// <param name="packageVersion">Output parameter for the package version.</param>
/// <returns>True if the package name and version were successfully retrieved, false otherwise.</returns>
private static bool GetPackageNameAndVersionFromAppx(string packagePath, out string name, out PackageVersion packageVersion)
{
// Todo: Implement this without interop if possible
return NativeMethods.GetPackageNameAndVersionFromAppx(packagePath, out name, out packageVersion);
}
[GeneratedRegex("(^.+\\.(appx|msix|msixbundle)$)", RegexOptions.IgnoreCase)]
private static partial Regex msixPackagePattern();
}
}

View File

@@ -1,30 +0,0 @@
// 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.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace RunnerV2.Helpers
{
internal static class ProcessHelper
{
internal static void ScheudleProcessKill(string processName, int msDelay = 500)
{
new Thread(async () =>
{
Process[] processes = Process.GetProcessesByName(processName);
await Task.Delay(msDelay);
foreach (var process in processes)
{
if (!process.HasExited)
{
process.Kill();
}
}
}).Start();
}
}
}

View File

@@ -1,228 +0,0 @@
// 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.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.IO.Pipelines;
using System.Linq;
using System.Text.Json;
using System.Threading;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.Interop;
using RunnerV2.Models;
using Update;
namespace RunnerV2.Helpers
{
/// <summary>
/// This class provides helper methods to interact with the PowerToys Settings window.
/// </summary>
internal static class SettingsHelper
{
private static readonly SettingsUtils _settingsUtils = SettingsUtils.Default;
private static Process? _process;
private static TwoWayPipeMessageIPCManaged? _ipc;
public static void OpenSettingsWindow(bool showOobeWindow = false, bool showScoobeWindow = false, bool showFlyout = false, Point? flyoutPosition = null, string? additionalArguments = null)
{
if (_process is not null && _ipc is not null && !_process.HasExited)
{
if (showFlyout)
{
_ipc.Send(@"{""ShowYourself"": ""flyout""}");
}
else
{
_ipc.Send($@"{{""ShowYourself"": ""{additionalArguments ?? "Dashboard"}""}}");
}
return;
}
_ipc?.End();
_ipc = null;
// Arg 1: Executable path
string executablePath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException("No executable path found"), "WinUI3Apps", "PowerToys.Settings.exe");
// Arg 2,3: Pipe names
Pipe settingsPipe = new();
Pipe powertoysPipe = new();
string powerToysPipeName = @"\\.\pipe\powertoys_runner_" + Guid.NewGuid();
string settingsPipeName = @"\\.\pipe\powertoys_settings_" + Guid.NewGuid();
// Arg 4: Process pid
string currentProcessId = Environment.ProcessId.ToString(CultureInfo.InvariantCulture);
// Arg 5: Settings theme
string theme = Program.GeneralSettings.Theme switch
{
"light" => "light",
"dark" => "dark",
"system" when ThemeHelpers.GetAppTheme() == AppTheme.Light => "light",
"system" when ThemeHelpers.GetAppTheme() == AppTheme.Dark => "dark",
_ => throw new NotImplementedException(),
};
// Arg 6: Elevated status
string isElevated = Program.GeneralSettings.IsElevated ? "true" : "false";
// Arg 7: Is user an administrator
string isAdmin = Program.GeneralSettings.IsAdmin ? "true" : "false";
// Arg 8: Show OOBE window
string showOobeArg = showOobeWindow ? "true" : "false";
// Arg 9: Show SCOOBE window
string showScoobeArg = showScoobeWindow ? "true" : "false";
// Arg 10: Show flyout
string showFlyoutArg = showFlyout ? "true" : "false";
// Arg 11: Are there additional settings window arguments
string areThereadditionalArgs = string.IsNullOrEmpty(additionalArguments) ? "false" : "true";
// Arg 12: Are there flyout position arguments
string areThereFlyoutPositionArgs = flyoutPosition.HasValue ? "true" : "false";
string executableArgs = $"{powerToysPipeName} {settingsPipeName} {currentProcessId} {theme} {isElevated} {isAdmin} {showOobeArg} {showScoobeArg} {showFlyoutArg} {areThereadditionalArgs} {areThereFlyoutPositionArgs}";
if (!string.IsNullOrEmpty(additionalArguments))
{
executableArgs += $" {additionalArguments}";
}
if (flyoutPosition is not null)
{
executableArgs += $" {flyoutPosition.Value.X} {flyoutPosition.Value.Y}";
}
_process = Process.Start(executablePath, executableArgs);
// Initialize listening to pipes
_ipc = new TwoWayPipeMessageIPCManaged(powerToysPipeName, settingsPipeName, OnSettingsMessageReceived);
_ipc.Start();
}
private static void OnSettingsMessageReceived(string message)
{
JsonDocument messageDocument = JsonDocument.Parse(message);
foreach (var property in messageDocument.RootElement.EnumerateObject())
{
switch (property.Name)
{
case "action":
foreach (var moduleName in property.Value.EnumerateObject())
{
_settingsUtils.SaveSettings(moduleName.Value.ToString(), moduleName.Name);
if (moduleName.Name == "general")
{
switch (moduleName.Value.GetProperty("action_name").GetString())
{
case "restart_elevation":
ElevationHelper.RestartScheduled = ElevationHelper.RestartScheduledMode.RestartElevatedWithOpenSettings;
Runner.Close();
break;
case "restart_mentain_elevation":
// Todo:
break;
case "check_for_updates":
UpdateSettingsHelper.TriggerUpdateCheck();
break;
case "request_update_state_date":
// Todo:
break;
}
break;
}
foreach (IPowerToysModule ptModule in Runner.LoadedModules)
{
if (ptModule is IPowerToysModuleCustomActionsProvider customActionsProvider && customActionsProvider.CustomActions.TryGetValue(moduleName.Value.GetProperty("action_name").GetString() ?? string.Empty, out Action? action))
{
action();
}
}
}
break;
case "get_all_hotkey_conflicts":
// Todo: Handle hotkey conflict
break;
case "bugreport":
TrayIconManager.ProcessTrayMenuCommand((nuint)TrayIconManager.TrayButton.ReportBug);
break;
case "bug_report_status":
_ipc?.Send($@"{{""bug_report_running:"" {(TrayIconManager.IsBugReportToolRunning ? "true" : "false")}");
break;
case "killrunner":
Runner.Close();
break;
case "general":
try
{
_settingsUtils.SaveSettings(property.Value.ToString(), string.Empty);
}
catch (Exception)
{
// TODO: Log error
}
NativeMethods.PostMessageW(Runner.RunnerHwnd, (uint)NativeMethods.WindowMessages.REFRESH_SETTINGS, 0, 0);
foreach (IPowerToysModule module in Runner.ModulesToLoad)
{
if (module is IPowerToysModuleSettingsChangedSubscriber settingsChangedSubscriber)
{
settingsChangedSubscriber.OnSettingsChanged();
}
}
break;
case "powertoys":
foreach (var powertoysSettingsPart in property.Value.EnumerateObject())
{
_settingsUtils.SaveSettings(powertoysSettingsPart.Value.ToString(), powertoysSettingsPart.Name);
if (Runner.LoadedModules.Find(m => m.Name == powertoysSettingsPart.Name) is IPowerToysModuleSettingsChangedSubscriber module)
{
module.OnSettingsChanged();
}
else
{
// If no specific module was found, notify all enabled modules
foreach (IPowerToysModule module2 in Runner.LoadedModules.Where(m => m.Enabled))
{
if (module2 is IPowerToysModuleSettingsChangedSubscriber settingsChangedSubscriber)
{
settingsChangedSubscriber.OnSettingsChanged();
}
}
}
NativeMethods.PostMessageW(Runner.RunnerHwnd, (uint)NativeMethods.WindowMessages.REFRESH_SETTINGS, 0, 0);
}
break;
default:
Console.WriteLine($"Unknown message received from Settings: {property.Name}");
break;
}
}
}
public static void CloseSettingsWindow()
{
using var closeEventWrapper = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerToysRunnerTerminateSettingsEvent());
closeEventWrapper.Set();
}
}
}

View File

@@ -1,150 +0,0 @@
// 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.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using static RunnerV2.NativeMethods;
namespace RunnerV2.Helpers
{
internal static partial class TrayIconManager
{
internal static void StartTrayIcon()
{
NOTIFYICONDATA notifyicondata = new()
{
CbSize = (uint)Marshal.SizeOf<NOTIFYICONDATA>(),
HWnd = Runner.RunnerHwnd,
UId = 1,
HIcon = Icon.ExtractAssociatedIcon(Environment.ProcessPath!)!.Handle,
UFlags = 0x0000001 | 0x00000002 | 0x4,
UCallbackMessage = (uint)WindowMessages.ICON_NOTIFY,
SzTip = "PowerToys Runner",
};
ChangeWindowMessageFilterEx(Runner.RunnerHwnd, 0x0111, 0x0001, IntPtr.Zero);
Shell_NotifyIcon(NIMADD, ref notifyicondata);
}
internal static void StopTrayIcon()
{
NOTIFYICONDATA notifyicondata = new()
{
CbSize = (uint)Marshal.SizeOf<NOTIFYICONDATA>(),
HWnd = Runner.RunnerHwnd,
UId = 1,
};
Shell_NotifyIcon(NIMDELETE, ref notifyicondata);
}
internal enum TrayButton : uint
{
Settings = 1,
Documentation,
ReportBug,
Close,
}
private static bool _doubleClickTimerRunning;
private static bool _doubleClickDetected;
private static IntPtr _trayIconMenu;
static TrayIconManager()
{
_trayIconMenu = CreatePopupMenu();
AppendMenuW(_trayIconMenu, 0u, new UIntPtr((uint)TrayButton.Settings), "Settings\tDouble-click");
AppendMenuW(_trayIconMenu, 0x00000800u, UIntPtr.Zero, string.Empty); // separator
AppendMenuW(_trayIconMenu, 0u, new UIntPtr((uint)TrayButton.Documentation), "Documentation");
AppendMenuW(_trayIconMenu, 0u, new UIntPtr((uint)TrayButton.ReportBug), "Report a Bug");
AppendMenuW(_trayIconMenu, 0x00000800u, UIntPtr.Zero, string.Empty); // separator
AppendMenuW(_trayIconMenu, 0u, new UIntPtr((uint)TrayButton.Close), "Close");
}
internal static void ProcessTrayIconMessage(long lParam)
{
switch (lParam)
{
case 0x0205: // WM_RBUTTONDBLCLK
case 0x007B: // WM_CONTEXTMENU
SetForegroundWindow(Runner.RunnerHwnd);
TrackPopupMenu(_trayIconMenu, 0x0004 | 0x0020, Cursor.Position.X, Cursor.Position.Y, 0, Runner.RunnerHwnd, IntPtr.Zero);
break;
case 0x0202: // WM_LBUTTONUP
if (_doubleClickTimerRunning)
{
break;
}
_doubleClickTimerRunning = true;
Task.Delay(SystemInformation.DoubleClickTime).ContinueWith(_ =>
{
if (!_doubleClickDetected)
{
SettingsHelper.OpenSettingsWindow(showFlyout: true, flyoutPosition: Cursor.Position);
}
_doubleClickDetected = false;
_doubleClickTimerRunning = false;
});
break;
case 0x0203: // WM_LBUTTONDBLCLK
_doubleClickDetected = true;
SettingsHelper.OpenSettingsWindow();
break;
}
}
internal static bool IsBugReportToolRunning { get; set; }
internal static void ProcessTrayMenuCommand(nuint commandId)
{
switch ((TrayButton)commandId)
{
case TrayButton.Settings:
SettingsHelper.OpenSettingsWindow();
break;
case TrayButton.Documentation:
Process.Start(new ProcessStartInfo
{
FileName = "https://aka.ms/PowerToysOverview",
UseShellExecute = true,
});
break;
case TrayButton.ReportBug:
Process bugReportProcess = new();
bugReportProcess.StartInfo = new ProcessStartInfo
{
FileName = "Tools\\PowerToys.BugReportTool.exe",
CreateNoWindow = true,
};
bugReportProcess.EnableRaisingEvents = true;
EnableMenuItem(_trayIconMenu, (uint)TrayButton.ReportBug, 0x000000 | 0x00001);
bugReportProcess.Exited += (sender, e) =>
{
bugReportProcess.Dispose();
EnableMenuItem(_trayIconMenu, (uint)TrayButton.ReportBug, 0x00000000);
IsBugReportToolRunning = false;
};
bugReportProcess.Start();
IsBugReportToolRunning = true;
break;
case TrayButton.Close:
Runner.Close();
break;
}
}
}
}

View File

@@ -1,47 +0,0 @@
// 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.Text.Json;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
namespace RunnerV2.Models
{
public interface IPowerToysModule
{
/// <summary>
/// Gets the short name of the module. The same used as the name of the folder containing its settings.
/// </summary>
public string Name { get; }
/// <summary>
/// This function is called when the module is enabled.
/// </summary>
public void Enable();
/// <summary>
/// This function is called when the module is disabled.
/// </summary>
public void Disable();
/// <summary>
/// Gets a value indicating whether the module is enabled.
/// </summary>
/// <remarks>
/// This value shall be read from the settings of the module in the module interface implementation.
/// </remarks>
public bool Enabled { get; }
/// <summary>
/// Gets the GPO rule configured state for the module.
/// </summary>
/// <remarks>
/// This value shall be read from the GPO settings with the <see cref="GPOWrapper"/> class.
/// </remarks>
public GpoRuleConfigured GpoRuleConfigured { get; }
}
}

View File

@@ -1,17 +0,0 @@
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RunnerV2.Models
{
internal interface IPowerToysModuleCustomActionsProvider
{
public Dictionary<string, Action> CustomActions { get; }
}
}

View File

@@ -1,17 +0,0 @@
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RunnerV2.Models
{
internal interface IPowerToysModuleSettingsChangedSubscriber
{
public void OnSettingsChanged();
}
}

View File

@@ -1,21 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
namespace RunnerV2.Models
{
internal interface IPowerToysModuleShortcutsProvider
{
/// <summary>
/// Gets a list of shortcuts, that shall be registered in the keyboard hook, and their associated actions.
/// </summary>
/// <remarks>
/// If this property is not overridden, the module is considered to not have shortcuts.
/// </remarks>
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; }
}
}

View File

@@ -1,168 +0,0 @@
// 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.Diagnostics;
using System.Globalization;
using RunnerV2.Helpers;
namespace RunnerV2.Models
{
/// <summary>
/// Base abstract class for modules that launch and manage external processes.
/// </summary>
internal abstract class ProcessModuleAbstractClass
{
/// <summary>
/// Options for launching a process.
/// </summary>
[Flags]
public enum ProcessLaunchOptions
{
/// <summary>
/// Only a single instance of the process should be running.
/// </summary>
SingletonProcess = 1,
/// <summary>
/// Elevate the process if the current process is elevated.
/// </summary>
ElevateIfApplicable = 2,
/// <summary>
/// Provide the runner process ID as the first argument to the launched process.
/// </summary>
RunnerProcessIdAsFirstArgument = 4,
/// <summary>
/// Indicates that the application should not launch automatically when the specified module is enabled.
/// </summary>
SupressLaunchOnModuleEnabled = 8,
/// <summary>
/// Specifies that the process should be started using the operating system shell.
/// </summary>
UseShellExecute = 16,
/// <summary>
/// Indicates that the process should never exit automatically.
/// </summary>
/// <remarks>Use this value when using a helper process to launch an application like explorer.exe.</remarks>
NeverExit = 32,
/// <summary>
/// Suppresses UI when process is launched.
/// </summary>
HideUI = 64,
/// <summary>
/// Sets the launched process to realtime priority.
/// </summary>
RealtimePriority = 128,
}
/// <summary>
/// Gets the relative or absolute path to the process executable.
/// </summary>
public abstract string ProcessPath { get; }
/// <summary>
/// Gets the name of the process without the .exe extension.
/// </summary>
/// <remarks>
/// Has no effect if the <see cref="LaunchOptions"/> has the <see cref="ProcessLaunchOptions.UseShellExecute"/> flag set.
/// </remarks>
public abstract string ProcessName { get; }
/// <summary>
/// Gets the arguments to pass to the process on launch.
/// </summary>
/// <remarks>
/// If not overridden, no arguments are passed.
/// If the <see cref="LaunchOptions"/> has the <see cref="ProcessLaunchOptions.RunnerProcessIdAsFirstArgument"/> flag is set, the runner process ID is prepended to these arguments.
/// </remarks>
public virtual string ProcessArguments { get; } = string.Empty;
/// <summary>
/// Gets the options used to configure how the process is launched.
/// </summary>
public abstract ProcessLaunchOptions LaunchOptions { get; }
/// <summary>
/// Ensures that atleast one process is launched. If the process is already running, does nothing.
/// </summary>
public void EnsureLaunched()
{
Process[] processes = Process.GetProcessesByName(ProcessName);
if (processes.Length > 0)
{
return;
}
LaunchProcess();
}
/// <summary>
/// Launches the process with the specified options.
/// </summary>
/// <param name="isModuleEnableProcess">Specifies if the <see cref="Runner"/> class is currently calling this function as part of a module startup</param>
public void LaunchProcess(bool isModuleEnableProcess = false)
{
if (isModuleEnableProcess && LaunchOptions.HasFlag(ProcessLaunchOptions.SupressLaunchOnModuleEnabled))
{
return;
}
if (LaunchOptions.HasFlag(ProcessLaunchOptions.SingletonProcess))
{
Process[] processes = Process.GetProcessesByName(ProcessName);
if (processes.Length > 0)
{
return;
}
}
string arguments = (LaunchOptions.HasFlag(ProcessLaunchOptions.RunnerProcessIdAsFirstArgument) ? Environment.ProcessId.ToString(CultureInfo.InvariantCulture) + (string.IsNullOrEmpty(ProcessArguments) ? string.Empty : " ") : string.Empty) + ProcessArguments;
Process? p = Process.Start(new ProcessStartInfo()
{
UseShellExecute = LaunchOptions.HasFlag(ProcessLaunchOptions.UseShellExecute),
FileName = ProcessPath,
Arguments = arguments,
Verb = LaunchOptions.HasFlag(ProcessLaunchOptions.ElevateIfApplicable) && ElevationHelper.IsProcessElevated() ? "runas" : "open",
});
if (LaunchOptions.HasFlag(ProcessLaunchOptions.RealtimePriority))
{
try
{
if (p != null && !p.HasExited)
{
p.PriorityClass = ProcessPriorityClass.RealTime;
}
}
catch (Exception ex)
{
Debug.WriteLine($"[ProcessModuleAbstractClass] Failed to set realtime priority for process {ProcessName}", ex);
}
}
}
/// <summary>
/// Schedules all processes with the specified <see cref="ProcessName"/>.
/// </summary>
/// <remarks>
/// If the <see cref="LaunchOptions"/> has the <see cref="ProcessLaunchOptions.NeverExit"/> flag set, this function does nothing.
/// </remarks>
public void ProcessExit()
{
if (LaunchOptions.HasFlag(ProcessLaunchOptions.NeverExit))
{
return;
}
ProcessHelper.ScheudleProcessKill(ProcessName);
}
}
}

View File

@@ -1,45 +0,0 @@
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RunnerV2.Models
{
internal readonly struct RegistryChangeSet
{
public RegistryValueChange[] Changes { get; init; }
public readonly bool IsApplied => Changes.All(c => c.IsApplied);
public readonly bool Apply()
{
bool allApplied = true;
foreach (var change in Changes)
{
allApplied = (change.Apply() || !change.Required) && allApplied;
}
return allApplied;
}
public readonly bool ApplyIfNotApplied() => IsApplied || Apply();
public readonly bool UnApplyIfApplied() => !IsApplied || UnApply();
public readonly bool UnApply()
{
bool allUnapplied = true;
foreach (var change in Changes)
{
allUnapplied = (change.UnApply() || !change.Required) && allUnapplied;
}
return allUnapplied;
}
}
}

View File

@@ -1,124 +0,0 @@
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.Win32;
namespace RunnerV2.Models
{
internal readonly struct RegistryValueChange
{
public RegistryValueChange()
{
}
public required string KeyPath { get; init; }
public required string? KeyName { get; init; }
public bool Required { get; init; } = true;
public required object Value { get; init; }
public RegistryHive Scope { get; init; } = RegistryHive.CurrentUser;
private static RegistryValueKind ValueTypeToRegistryValueKind(object value)
{
return value switch
{
int => RegistryValueKind.DWord,
long => RegistryValueKind.QWord,
string => RegistryValueKind.String,
string[] => RegistryValueKind.MultiString,
byte[] => RegistryValueKind.Binary,
_ => throw new ArgumentException("Unsupported value type"),
};
}
public readonly bool IsApplied
{
get
{
try
{
using RegistryKey? key = RegistryKey.OpenBaseKey(Scope, RegistryView.Default).OpenSubKey(KeyPath, false);
return key != null && ValueTypeToRegistryValueKind(Value) == key.GetValueKind(KeyName) && Value.Equals(key.GetValue(KeyName));
}
catch (Exception e)
{
Logger.LogError($"Testing if registry change \"{this}\" is applied failed.", e);
return false;
}
}
}
public readonly bool RequiresElevation
{
get => Scope == RegistryHive.LocalMachine;
}
public readonly bool Apply()
{
try
{
using RegistryKey? key = RegistryKey.OpenBaseKey(Scope, RegistryView.Default).CreateSubKey(KeyPath, true);
if (key == null)
{
Logger.LogError($"Applying registry change \"{this}\" failed because the registry key could not be created.");
return false;
}
key.SetValue(KeyName, Value, ValueTypeToRegistryValueKind(Value));
return true;
}
catch (Exception e)
{
Logger.LogError($"Applying registry change \"{this}\" failed.", e);
return false;
}
}
public readonly bool UnApply()
{
try
{
using RegistryKey? key = RegistryKey.OpenBaseKey(Scope, RegistryView.Default).OpenSubKey(KeyPath, true);
if (key == null)
{
Logger.LogError($"Unapplying registry change \"{this}\" failed because the registry key could not be opened.");
return false;
}
if (KeyName is not null)
{
key.DeleteValue(KeyName, false);
}
else
{
key.SetValue(null, string.Empty); // Delete the default value
}
// Check if the path doesn't contain anything and delete it if so
if (key.GetValueNames().Length == 0 && key.GetSubKeyNames().Length == 0)
{
RegistryKey.OpenBaseKey(Scope, RegistryView.Default).DeleteSubKey(KeyPath, false);
}
return true;
}
catch (Exception e)
{
Logger.LogError($"Unapplying registry change \"{this}\" failed.", e);
return false;
}
}
public override readonly string ToString() => $"{RegistryKey.OpenBaseKey(Scope, RegistryView.Default).Name}\\{KeyPath}\\{KeyName}:{Value}";
}
}

View File

@@ -1,16 +0,0 @@
// 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.
namespace RunnerV2.Models
{
internal enum SpecialMode
{
None,
Win32ToastNotificationCOMServer,
DisableCantDragElevatedNotification,
UpdateNow,
ReportSuccessfulUpdate,
CouldntToggleFileExplorerModulesNotification,
}
}

View File

@@ -1,107 +0,0 @@
// 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.Linq;
using System.Text.Json;
using System.Windows.Forms;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class AdvancedPasteModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IDisposable, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "AdvancedPaste";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.AdvancedPaste;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredAdvancedPasteEnabledValue();
public void Disable()
{
if (_ipc != null)
{
_ipc.Send(Constants.AdvancedPasteTerminateAppMessage());
_ipc.End();
_ipc = null;
}
}
private const string IpcName = @"\\.\pipe\PowerToys.AdvancedPaste";
private TwoWayPipeMessageIPCManaged? _ipc;
public void Enable()
{
_ipc = new TwoWayPipeMessageIPCManaged(string.Empty, IpcName, (_) => { });
_ipc.Start();
PopulateShortcuts();
}
public void OnSettingsChanged()
{
PopulateShortcuts();
}
public void PopulateShortcuts()
{
_ipc ??= new TwoWayPipeMessageIPCManaged(string.Empty, @"\\.\pipe\PowerToys.AdvancedPaste", (_) => { });
Shortcuts.Clear();
AdvancedPasteSettings settings = SettingsUtils.Default.GetSettingsOrDefault<AdvancedPasteSettings>(Name);
Shortcuts.Add((settings.Properties.AdvancedPasteUIShortcut, () =>
_ipc.Send(Constants.AdvancedPasteShowUIMessage())
));
Shortcuts.Add((settings.Properties.PasteAsPlainTextShortcut, TryToPasteAsPlainText));
Shortcuts.Add((settings.Properties.PasteAsMarkdownShortcut, () => _ipc.Send(Constants.AdvancedPasteMarkdownMessage())));
Shortcuts.Add((settings.Properties.PasteAsJsonShortcut, () => _ipc.Send(Constants.AdvancedPasteJsonMessage())));
HotkeyAccessor[] hotkeyAccessors = settings.GetAllHotkeyAccessors();
int additionalActionsCount = settings.Properties.AdditionalActions.GetAllActions().Count() - 2;
for (int i = 0; i < additionalActionsCount; i++)
{
int scopedI = i;
Shortcuts.Add((hotkeyAccessors[4 + i].Value, () => _ipc.Send(Constants.AdvancedPasteAdditionalActionMessage() + " " + (3 + scopedI))));
}
for (int i = 4 + additionalActionsCount; i < hotkeyAccessors.Length; i++)
{
int scopedI = i;
Shortcuts.Add((hotkeyAccessors[i].Value, () => _ipc.Send(Constants.AdvancedPasteCustomActionMessage() + " " + (scopedI - 4 - additionalActionsCount))));
}
}
private void TryToPasteAsPlainText()
{
if (Clipboard.ContainsText())
{
string text = Clipboard.GetText();
SendKeys.SendWait(text);
}
throw new NotImplementedException();
}
public void Dispose()
{
_ipc?.Dispose();
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
public override string ProcessPath => "WinUI3Apps\\PowerToys.AdvancedPaste.exe";
public override string ProcessName => "PowerToys.AdvancedPaste";
public override string ProcessArguments => IpcName;
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument;
}
}

View File

@@ -1,59 +0,0 @@
// 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.Text.Json;
using System.Threading;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class AlwaysOnTopModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.AlwaysOnTop;
public string Name => "AlwaysOnTop";
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue();
public void Disable()
{
using var terminateEventWrapper = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.AlwaysOnTopTerminateEvent());
terminateEventWrapper.Set();
}
public void Enable()
{
InitializeHotkey();
}
private void InitializeHotkey()
{
Shortcuts.Clear();
Shortcuts.Add((SettingsUtils.Default.GetSettings<AlwaysOnTopSettings>(Name).Properties.Hotkey.Value, () =>
{
using var pinEventWrapper = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.AlwaysOnTopPinEvent());
pinEventWrapper.Set();
}
));
}
public void OnSettingsChanged()
{
InitializeHotkey();
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
public override string ProcessPath => "PowerToys.AlwaysOnTop.exe";
public override string ProcessName => "PowerToys.AlwaysOnTop";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument | ProcessLaunchOptions.ElevateIfApplicable;
}
}

View File

@@ -1,41 +0,0 @@
// 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.Globalization;
using System.Threading;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class AwakeModuleInterface : ProcessModuleAbstractClass, IPowerToysModule
{
public string Name => "Awake";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.Awake;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredAwakeEnabledValue();
public override string ProcessPath => "PowerToys.Awake.exe";
public override string ProcessName => "PowerToys.Awake";
public override string ProcessArguments => $"--use-pt-config --pid {Environment.ProcessId.ToString(CultureInfo.InvariantCulture)}";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess;
public void Disable()
{
using var terminateEventWrapper = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.AwakeExitEvent());
terminateEventWrapper.Set();
}
public void Enable()
{
}
}
}

View File

@@ -1,80 +0,0 @@
// 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.Diagnostics;
using System.IO;
using System.Threading;
using ManagedCommon;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class CmdNotFoundModuleInterface : IPowerToysModule
{
public string Name => "CmdNotFound";
public bool Enabled => true;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredCmdNotFoundEnabledValue();
public CmdNotFoundModuleInterface()
{
if (GpoRuleConfigured == GpoRuleConfigured.Disabled)
{
UninstallModule();
}
if (GpoRuleConfigured == GpoRuleConfigured.Enabled)
{
InstallModule();
}
}
public void InstallModule()
{
Logger.LogInfo("Installing Command Not Found module invoked through GPO");
new Thread(async () =>
{
Process p = Process.Start("pwsh.exe", "-NoProfile -NonInteractive -NoLogo -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + Path.GetDirectoryName(Environment.ProcessPath) + "\\WinUI3Apps\\Assets\\Settings\\Scripts\\EnableModule.ps1" + "\"" + " -scriptPath \"" + Path.GetDirectoryName(Environment.ProcessPath) + "\"");
await p.WaitForExitAsync();
if (p.ExitCode == 0)
{
Logger.LogInfo("Command Not Found was successfully installed.");
return;
}
Logger.LogInfo("Command Not Found failed to install with exit code: " + p.ExitCode);
}).Start();
}
public void UninstallModule()
{
Logger.LogInfo("Uninstalling Command Not Found module invoked through GPO");
new Thread(async () =>
{
Process p = Process.Start("pwsh.exe", "-NoProfile -NonInteractive -NoLogo -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + Path.GetDirectoryName(Environment.ProcessPath) + "\\WinUI3Apps\\Assets\\Settings\\Scripts\\DisableModule.ps1" + "\"" + " -scriptPath \"" + Path.GetDirectoryName(Environment.ProcessPath) + "\"");
await p.WaitForExitAsync();
if (p.ExitCode == 0)
{
Logger.LogInfo("Command Not Found was successfully uninstalled.");
return;
}
Logger.LogInfo("Command Not Found failed to uninstall with exit code: " + p.ExitCode);
}).Start();
}
public void Disable()
{
}
public void Enable()
{
}
}
}

View File

@@ -1,59 +0,0 @@
// 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.Text.Json;
using System.Threading;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class ColorPickerModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "ColorPicker";
public bool Enabled => SettingsUtils.Default.GetSettingsOrDefault<GeneralSettings>().Enabled.ColorPicker;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredColorPickerEnabledValue();
public void Disable()
{
using var terminateEventWrapper = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.TerminateColorPickerSharedEvent());
terminateEventWrapper.Set();
}
public void Enable()
{
InitializeShortcuts();
}
private void InitializeShortcuts()
{
Shortcuts.Clear();
Shortcuts.Add((SettingsUtils.Default.GetSettings<ColorPickerSettings>(Name).Properties.ActivationShortcut, () =>
{
using var showUiEventWrapper = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowColorPickerSharedEvent());
showUiEventWrapper.Set();
}
));
}
public void OnSettingsChanged()
{
InitializeShortcuts();
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
public override string ProcessPath => "PowerToys.ColorPickerUI.exe";
public override string ProcessName => "PowerToys.ColorPickerUI";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument;
}
}

View File

@@ -1,79 +0,0 @@
// 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.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Helpers;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class CommandPaletteModuleInterface : ProcessModuleAbstractClass, IPowerToysModule
{
private const string PackageName = "Microsoft.CommandPalette"
#if DEBUG
+ ".Dev"
#endif
;
public string Name => "CmdPal";
public bool Enabled => SettingsUtils.Default.GetSettingsOrDefault<GeneralSettings>().Enabled.CmdPal;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredCmdPalEnabledValue();
public override string ProcessPath => "explorer.exe";
public override string ProcessArguments => "x-cmdpal://background";
public override string ProcessName => string.Empty;
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.UseShellExecute | ProcessLaunchOptions.NeverExit;
public void Disable()
{
}
public void Enable()
{
if (PackageHelper.GetRegisteredPackage(PackageName, false) is null)
{
try
{
string architectureString = RuntimeInformation.ProcessArchitecture == Architecture.X64 ? "x64" : "ARM64";
#if DEBUG
string[] msixFiles = PackageHelper.FindMsixFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\WinUI3Apps\\CmdPal\\AppPackages\\Microsoft.CmdPal.UI_0.0.1.0_Debug_Test\\", false);
string[] dependencies = PackageHelper.FindMsixFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\WinUI3Apps\\CmdPal\\AppPackages\\Microsoft.CmdPal.UI_0.0.1.0_Debug_Test\\Dependencies\\" + architectureString + "\\", true);
#else
string[] msixFiles = PackageHelper.FindMsixFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\WinUI3Apps\\CmdPal\\", false);
string[] dependencies = PackageHelper.FindMsixFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\WinUI3Apps\\CmdPal\\Dependencies\\", true);
#endif
if (msixFiles.Length > 0)
{
if (!PackageHelper.InstallPackage(msixFiles[0], dependencies))
{
Logger.LogError("Failed to register Command Palette package.");
}
}
}
catch (Exception ex)
{
Logger.LogError("Exception occurred while enabling Command Palette package.", ex);
}
}
if (PackageHelper.GetRegisteredPackage(PackageName, false) is null)
{
Logger.LogError("Command Palette package is not registered after attempting to enable it.");
return;
}
}
}
}

View File

@@ -1,68 +0,0 @@
// 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.Text.Json;
using System.Threading;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed partial class CropAndLockModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IDisposable, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "CropAndLock";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.CropAndLock;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredCropAndLockEnabledValue();
private EventWaitHandle _reparentEvent = new(false, EventResetMode.AutoReset, Constants.CropAndLockReparentEvent());
private EventWaitHandle _thumbnailEvent = new(false, EventResetMode.AutoReset, Constants.CropAndLockThumbnailEvent());
private EventWaitHandle _terminateEvent = new(false, EventResetMode.AutoReset, Constants.CropAndLockExitEvent());
public void Disable()
{
_terminateEvent.Set();
}
public void Enable()
{
PopulateShortcuts();
}
public void PopulateShortcuts()
{
Shortcuts.Clear();
var settings = SettingsUtils.Default.GetSettings<CropAndLockSettings>(Name);
Shortcuts.Add((settings.Properties.ThumbnailHotkey.Value, () => _thumbnailEvent.Set()));
Shortcuts.Add((settings.Properties.ReparentHotkey.Value, () => _reparentEvent.Set()));
}
public void OnSettingsChanged()
{
PopulateShortcuts();
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
public override string ProcessPath => "PowerToys.CropAndLock.exe";
public override string ProcessName => "PowerToys.CropAndLock";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument;
public void Dispose()
{
GC.SuppressFinalize(this);
_reparentEvent.Dispose();
_thumbnailEvent.Dispose();
_terminateEvent.Dispose();
}
}
}

View File

@@ -1,69 +0,0 @@
// 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.Runtime.InteropServices;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class CursorWrapModuleInterface : IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "CursorWrap";
private bool _hookActive;
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.CursorWrap;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredCursorWrapEnabledValue();
public void Disable()
{
_hookActive = false;
CursorWrapStopMouseHook();
}
public void Enable()
{
InitializeShortcuts();
_hookActive = true;
CursorWrapStartMouseHook();
}
public void OnSettingsChanged()
{
InitializeShortcuts();
}
private void InitializeShortcuts()
{
Shortcuts.Clear();
Shortcuts.Add((SettingsUtils.Default.GetSettings<CursorWrapSettings>(Name).Properties.DefaultActivationShortcut, () =>
{
if (_hookActive)
{
CursorWrapStopMouseHook();
_hookActive = false;
}
else
{
CursorWrapStartMouseHook();
_hookActive = true;
}
}));
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
[DllImport("PowerToys.CursorWrap.dll")]
private static extern bool CursorWrapStartMouseHook();
[DllImport("PowerToys.CursorWrap.dll")]
private static extern bool CursorWrapStopMouseHook();
}
}

View File

@@ -1,33 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class EnvironmentVariablesModuleInterface : ProcessModuleAbstractClass, IPowerToysModule
{
public string Name => "Environment Variables";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.EnvironmentVariables;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredEnvironmentVariablesEnabledValue();
public override string ProcessPath => "WinUI3Apps\\PowerToys.EnvironmentVariables.exe";
public override string ProcessName => "PowerToys.EnvironmentVariables";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SupressLaunchOnModuleEnabled | ProcessLaunchOptions.NeverExit;
public void Disable()
{
}
public void Enable()
{
}
}
}

View File

@@ -1,72 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class FancyZonesModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleCustomActionsProvider, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "FancyZones";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.FancyZones;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredFancyZonesEnabledValue();
public override string ProcessPath => "PowerToys.FancyZones.exe";
public override string ProcessName => "PowerToys.FancyZones";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument | ProcessLaunchOptions.HideUI;
public void Disable()
{
using var terminateEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset, Constants.FZEExitEvent());
terminateEvent.Set();
}
public void Enable()
{
InitializeShortcuts();
}
public Dictionary<string, Action> CustomActions => new()
{
{
"ToggledFZEditor",
() =>
{
EnsureLaunched();
using var invokeFZEditorEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset, Constants.FZEToggleEvent());
invokeFZEditorEvent.Set();
}
},
};
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
public void InitializeShortcuts()
{
Shortcuts.Clear();
var settings = SettingsUtils.Default.GetSettings<FancyZonesSettings>(Name);
Shortcuts.Add((settings.Properties.FancyzonesEditorHotkey.Value, () =>
{
EnsureLaunched();
using var invokeFZEditorEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset, Constants.FZEToggleEvent());
invokeFZEditorEvent.Set();
}
));
}
public void OnSettingsChanged()
{
InitializeShortcuts();
}
}
}

View File

@@ -1,331 +0,0 @@
// 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 System.Reflection;
using System.Text.Json;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class FileExplorerModuleInterface : IPowerToysModule, IPowerToysModuleSettingsChangedSubscriber
{
private record struct FileExplorerModule(Func<bool> IsEnabled, GpoRuleConfigured GpoRule, RegistryChangeSet RegistryChanges);
private static readonly List<FileExplorerModule> _fileExplorerModules;
private static readonly string[] ExtSVG = { ".svg" };
private static readonly string[] ExtMarkdown = { ".md", ".markdown", ".mdown", ".mkdn", ".mkd", ".mdwn", ".mdtxt", ".mdtext" };
private static readonly string[] ExtPDF = { ".pdf" };
private static readonly string[] ExtGCode = { ".gcode" };
private static readonly string[] ExtBGCode = { ".bgcode" };
private static readonly string[] ExtSTL = { ".stl" };
private static readonly string[] ExtQOI = { ".qoi" };
static FileExplorerModuleInterface()
{
static PowerPreviewProperties GetProperties() => SettingsUtils.Default.GetSettings<PowerPreviewSettings>(PowerPreviewSettings.ModuleName).Properties;
string installationPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
_fileExplorerModules = [
new FileExplorerModule(
() => GetProperties().EnableBgcodePreview,
GPOWrapper.GetConfiguredBgcodePreviewEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.PreviewHandler, "{0e6d5bdd-d5f8-4692-a089-8bb88cdd37f4}", "BgcodePreviewHandler", "Binary G-code Preview Handler", ExtBGCode)),
new FileExplorerModule(
() => GetProperties().EnableBgcodeThumbnail,
GPOWrapper.GetConfiguredBgcodeThumbnailsEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.ThumbnailProvider, "{5c93a1e4-99d0-4fb3-991c-6c296a27be21}", "BgcodeThumbnailProvider", "Binary G-code Thumbnail Provider", ExtBGCode)),
new FileExplorerModule(
() => GetProperties().EnableGcodePreview,
GPOWrapper.GetConfiguredGcodePreviewEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.PreviewHandler, "{A0257634-8812-4CE8-AF11-FA69ACAEAFAE}", "GcodePreviewHandler", "G-code Preview Handler", ExtGCode)),
new FileExplorerModule(
() => GetProperties().EnableGcodeThumbnail,
GPOWrapper.GetConfiguredGcodeThumbnailsEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.ThumbnailProvider, "{F2847CBE-CD03-4C83-A359-1A8052C1B9D5}", "GcodeThumbnailProvider", "G-code Thumbnail Provider", ExtGCode)),
new FileExplorerModule(
() => GetProperties().EnableMdPreview,
GPOWrapper.GetConfiguredMarkdownPreviewEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.PreviewHandler, "{60789D87-9C3C-44AF-B18C-3DE2C2820ED3}", "MarkdownPreviewHandler", "Markdown Preview Handler", ExtMarkdown)),
new FileExplorerModule(
() => GetProperties().EnablePdfPreview,
GPOWrapper.GetConfiguredPdfPreviewEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.PreviewHandler, "{A5A41CC7-02CB-41D4-8C9B-9087040D6098}", "PdfPreviewHandler", "PDF Preview Handler", ExtPDF)),
new FileExplorerModule(
() => GetProperties().EnablePdfThumbnail,
GPOWrapper.GetConfiguredPdfThumbnailsEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.ThumbnailProvider, "{D8BB9942-93BD-412D-87E4-33FAB214DC1A}", "PdfThumbnailProvider", "PDF Thumbnail Provider", ExtPDF)),
new FileExplorerModule(
() => GetProperties().EnableQoiPreview,
GPOWrapper.GetConfiguredQoiPreviewEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.PreviewHandler, "{729B72CD-B72E-4FE9-BCBF-E954B33FE699}", "QoiPreviewHandler", "QOI Preview Handler", ExtQOI)),
new FileExplorerModule(
() => GetProperties().EnableQoiThumbnail,
GPOWrapper.GetConfiguredQoiThumbnailsEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.ThumbnailProvider, "{AD856B15-D25E-4008-AFB7-AFAA55586188}", "QoiThumbnailProvider", "QOI Thumbnail Provider", ExtQOI, "image", "Picture")),
new FileExplorerModule(
() => GetProperties().EnableStlThumbnail,
GPOWrapper.GetConfiguredStlThumbnailsEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.ThumbnailProvider, "{77257004-6F25-4521-B602-50ECC6EC62A6}", "StlThumbnailProvider", "STL Thumbnail Provider", ExtSTL)),
new FileExplorerModule(
() => GetProperties().EnableSvgPreview,
GPOWrapper.GetConfiguredSvgPreviewEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.PreviewHandler, "{FCDD4EED-41AA-492F-8A84-31A1546226E0}", "SvgPreviewHandler", "SVG Preview Handler", ExtSVG)),
new FileExplorerModule(
() => GetProperties().EnableSvgThumbnail,
GPOWrapper.GetConfiguredSvgThumbnailsEnabledValue(),
GetFileExplorerAddOnChangeSet(FileExplorerAddOnType.ThumbnailProvider, "{10144713-1526-46C9-88DA-1FB52807A9FF}", "SvgThumbnailProvider", "SVG Thumbnail Provider", ExtSVG, "image", "Picture")),
GetMonacoFileExplorerModule(installationPath)
];
}
private static FileExplorerModule GetMonacoFileExplorerModule(string installationPath)
{
// .svgz is a binary file type that Monaco cannot handle, so we exclude it from the preview handler
string[] extExclusions = [..ExtMarkdown, ..ExtSVG, ".svgz"];
List<string> extensions = [];
string languagesFilePath = Path.Combine(installationPath, "Assets\\Monaco\\monaco_languages.json");
if (!File.Exists(languagesFilePath))
{
Logger.LogError("PowerPreviewModuleInterface: Unable to find monaco_languages.json file at " + languagesFilePath);
goto returnLabel;
}
try
{
JsonDocument jsonDocument = JsonDocument.Parse(File.ReadAllText(languagesFilePath));
var list = jsonDocument.RootElement.GetProperty("list");
foreach (var item in list.EnumerateArray())
{
if (item.TryGetProperty("extensions", out JsonElement extensionsElement))
{
foreach (var ext in extensionsElement.EnumerateArray())
{
string extension = ext.GetString() ?? string.Empty;
if (!string.IsNullOrEmpty(extension) && !extensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
{
extensions.Add(extension);
}
}
}
}
}
catch (Exception ex)
{
Logger.LogError("PowerPreviewModuleInterface: Failed to parse monaco_languages.json file.", ex);
}
returnLabel:
return new FileExplorerModule(
() => SettingsUtils.Default.GetSettings<PowerPreviewSettings>(PowerPreviewSettings.ModuleName).Properties.EnableMonacoPreview,
GPOWrapper.GetConfiguredMonacoPreviewEnabledValue(),
GetFileExplorerAddOnChangeSet(
FileExplorerAddOnType.PreviewHandler,
"{D8034CFA-F34B-41FE-AD45-62FCBB52A6DA}",
"MonacoPreviewHandler",
"Monaco Preview Handler",
[.. extensions.Where(ext => !extExclusions.Contains(ext))]));
}
private enum FileExplorerAddOnType
{
ThumbnailProvider,
PreviewHandler,
}
private static RegistryChangeSet GetFileExplorerAddOnChangeSet(FileExplorerAddOnType type, string handlerClsid, string className, string displayName, string[] fileTypes, string? perceivedType = null, string? fileKindType = null)
{
string installationPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
string pathToHandler = Path.Combine(installationPath, "PowerToys.FileExplorerDllExporter.dll");
string clsidPath = "Software\\Classes\\CLSID\\" + handlerClsid;
string inprocServer32Path = clsidPath + "\\InprocServer32";
string assemblyKeyValue;
int lastDotPos = className.LastIndexOf('.');
if (lastDotPos != -1)
{
assemblyKeyValue = string.Concat("PowerToys.", className.AsSpan(lastDotPos + 1));
}
else
{
assemblyKeyValue = "PowerToys." + className;
}
assemblyKeyValue += $", Version={Assembly.GetExecutingAssembly().GetName().Version!}, Culture=neutral";
List<RegistryValueChange> changes = [
new RegistryValueChange
{
KeyPath = clsidPath,
KeyName = "DisplayName",
Value = displayName,
},
new RegistryValueChange
{
KeyPath = clsidPath,
KeyName = null,
Value = className,
},
new RegistryValueChange
{
KeyPath = inprocServer32Path,
KeyName = null,
Value = pathToHandler,
},
new RegistryValueChange
{
KeyPath = inprocServer32Path,
KeyName = "Assembly",
Value = assemblyKeyValue,
},
new RegistryValueChange
{
KeyPath = inprocServer32Path,
KeyName = "Class",
Value = className,
},
new RegistryValueChange
{
KeyPath = inprocServer32Path,
KeyName = "ThreadingModel",
Value = "Apartment",
},
];
foreach (string fileType in fileTypes)
{
string fileTypePath = "Software\\Classes\\" + fileType;
string fileAssociationPath = fileTypePath + "\\shellex\\" + (type == FileExplorerAddOnType.PreviewHandler ? IPREVIEWHANDLERCLSID : ITHUMBNAILPROVIDERCLSID);
changes.Add(new RegistryValueChange
{
KeyPath = fileAssociationPath,
KeyName = null,
Value = handlerClsid,
});
if (!string.IsNullOrEmpty(fileKindType))
{
// Registering a file type as a kind needs to be done at the HKEY_LOCAL_MACHINE level.
// Make it optional as well so that we don't fail registering the handler if we can't write to HKEY_LOCAL_MACHINE.
string kindPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap";
changes.Add(new RegistryValueChange
{
Scope = Microsoft.Win32.RegistryHive.LocalMachine,
KeyPath = kindPath,
KeyName = fileType,
Value = fileKindType,
Required = false,
});
}
if (!string.IsNullOrEmpty(perceivedType))
{
changes.Add(new RegistryValueChange
{
KeyPath = fileTypePath,
KeyName = "PerceivedType",
Value = perceivedType,
});
}
// this regfile registry key has precedence over Software\Classes\.reg for .reg files
if (type == FileExplorerAddOnType.PreviewHandler && fileType.Equals(".reg", StringComparison.OrdinalIgnoreCase))
{
string regFilePath = "Software\\Classes\\regfile\\shellex\\" + IPREVIEWHANDLERCLSID;
changes.Add(new RegistryValueChange
{
KeyPath = regFilePath,
KeyName = null,
Value = handlerClsid,
});
}
}
if (type == FileExplorerAddOnType.PreviewHandler)
{
string previewHostClsid = "{6d2b5079-2f0b-48dd-ab7f-97cec514d30b}";
string previewHandlerListPath = "(Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers)";
changes.Add(new RegistryValueChange
{
KeyPath = clsidPath,
KeyName = "AppID",
Value = previewHostClsid,
});
changes.Add(new RegistryValueChange
{
KeyPath = previewHandlerListPath,
KeyName = handlerClsid,
Value = displayName,
});
}
changes.Add(new RegistryValueChange
{
Scope = Microsoft.Win32.RegistryHive.LocalMachine,
KeyPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
KeyName = handlerClsid,
Value = displayName,
Required = false,
});
return new RegistryChangeSet
{
Changes = [.. changes],
};
}
private const string ITHUMBNAILPROVIDERCLSID = "{E357FCCD-A995-4576-B01F-234630154E96}";
private const string IPREVIEWHANDLERCLSID = "{8895b1c6-b41f-4c1c-a562-0d564250836f}";
public string Name => "File Explorer";
public bool Enabled => true;
public GpoRuleConfigured GpoRuleConfigured => GpoRuleConfigured.Unavailable;
public void Disable()
{
}
public void Enable()
{
OnSettingsChanged();
}
public void OnSettingsChanged()
{
foreach (FileExplorerModule submodule in _fileExplorerModules)
{
if (submodule.GpoRule == GpoRuleConfigured.Disabled)
{
submodule.RegistryChanges.UnApply();
continue;
}
if (submodule.IsEnabled() || submodule.GpoRule == GpoRuleConfigured.Enabled)
{
submodule.RegistryChanges.Apply();
}
else
{
submodule.RegistryChanges.UnApply();
}
}
}
}
}

View File

@@ -1,86 +0,0 @@
// 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.Runtime.InteropServices;
using System.Text.Json;
using System.Threading;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class FindMyMouseModuleInterface : IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "FindMyMouse";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.FindMyMouse;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredFindMyMouseEnabledValue();
public void Disable()
{
FindMyMouseDisable();
}
public void Enable()
{
InitializeShortcuts();
var thread = new Thread(() =>
{
uint version = 0x00010008;
int hr = MddBootstrapInitialize(version, 0, IntPtr.Zero);
if (hr < 0)
{
throw new InvalidOperationException($"Windows app sdk could not be initialized for MouseJump. HR code:{hr}");
}
FindMyMouseMain();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
public void OnSettingsChanged()
{
InitializeShortcuts();
NativeMethods.PostMessageW(GetSonarHwnd(), GetWmPrivSettingsChanged(), IntPtr.Zero, IntPtr.Zero);
}
private void InitializeShortcuts()
{
Shortcuts.Clear();
Shortcuts.Add((SettingsUtils.Default.GetSettings<FindMyMouseSettings>(Name).Properties.ActivationShortcut, () =>
{
NativeMethods.PostMessageW(GetSonarHwnd(), GetWmPrivShortcut(), IntPtr.Zero, IntPtr.Zero);
}
));
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
[DllImport("PowerToys.FindMyMouse.dll")]
public static extern void FindMyMouseMain();
[DllImport("PowerToys.FindMyMouse.dll")]
public static extern void FindMyMouseDisable();
[DllImport("PowerToys.FindMyMouse.dll")]
public static extern IntPtr GetSonarHwnd();
[DllImport("PowerToys.FindMyMouse.dll")]
public static extern uint GetWmPrivShortcut();
[DllImport("PowerToys.FindMyMouse.dll")]
public static extern uint GetWmPrivSettingsChanged();
[DllImport("Microsoft.WindowsAppRuntime.Bootstrap.dll", CharSet = CharSet.Unicode)]
private static extern int MddBootstrapInitialize(uint majorMinorVersion, uint versionTag, IntPtr packageVersion);
}
}

View File

@@ -1,35 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class HostsModuleInterface : ProcessModuleAbstractClass, IPowerToysModule
{
public bool Enabled => SettingsUtils.Default.GetSettingsOrDefault<GeneralSettings>().Enabled.Hosts;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredHostsFileEditorEnabledValue();
public string Name => "Hosts";
public override string ProcessPath => "WinUI3Apps\\PowerToys.Hosts.exe";
public override string ProcessName => "PowerToys.Hosts";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SupressLaunchOnModuleEnabled | ProcessLaunchOptions.NeverExit;
public void Disable()
{
}
public void Enable()
{
}
}
}

View File

@@ -1,38 +0,0 @@
// 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.Threading;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class KeyboardManagerModuleInterface : ProcessModuleAbstractClass, IPowerToysModule
{
public string Name => "Keyboard Manager";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.KeyboardManager;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredKeyboardManagerEnabledValue();
public override string ProcessPath => "KeyboardManagerEngine\\PowerToys.KeyboardManagerEngine.exe";
public override string ProcessName => "PowerToys.KeyboardManagerEngine";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument | ProcessLaunchOptions.RealtimePriority;
public void Disable()
{
using var terminateEvent = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.TerminateKBMSharedEvent());
terminateEvent.Set();
}
public void Enable()
{
}
}
}

View File

@@ -1,60 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
using Settings.UI.Library;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class LightSwitchModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleShortcutsProvider
{
public string Name => "LightSwitch";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.LightSwitch;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredLightSwitchEnabledValue();
public override string ProcessPath => "LightSwitchService\\PowerToys.LightSwitchService.exe";
public override string ProcessName => "PowerToys.LightSwitchService";
public override string ProcessArguments => $"--pid {Environment.ProcessId}";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess;
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts
{
get => [(SettingsUtils.Default.GetSettings<LightSwitchSettings>(Name).Properties.ToggleThemeHotkey.Value, () =>
{
LightSwitchProperties properties = SettingsUtils.Default.GetSettings<LightSwitchSettings>(Name).Properties;
EnsureLaunched();
if (properties.ChangeSystem.Value)
{
ThemeHelper.SetSystemTheme(!ThemeHelper.GetCurrentSystemTheme());
}
if (properties.ChangeApps.Value)
{
ThemeHelper.SetAppsTheme(!ThemeHelper.GetCurrentAppsTheme());
}
using var manualOverrideEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset, Constants.LightSwitchManualOverrideEvent());
manualOverrideEvent.Set();
})];
}
public void Disable()
{
}
public void Enable()
{
}
}
}

View File

@@ -1,54 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class MeasureToolModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "Measure Tool";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.MeasureTool;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredScreenRulerEnabledValue();
public override string ProcessPath => "WinUI3Apps\\PowerToys.MeasureToolUI.exe";
public override string ProcessName => "PowerToys.MeasureToolUI";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument | ProcessLaunchOptions.SupressLaunchOnModuleEnabled;
public void Disable()
{
}
public void Enable()
{
PopulateShortcuts();
}
public void OnSettingsChanged()
{
PopulateShortcuts();
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
private void PopulateShortcuts()
{
Shortcuts.Clear();
Shortcuts.Add((SettingsUtils.Default.GetSettings<MeasureToolSettings>(Name).Properties.ActivationShortcut, () =>
{
LaunchProcess();
}
));
}
}
}

View File

@@ -1,58 +0,0 @@
// 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.Runtime.InteropServices;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed partial class MouseHighlighterModuleInterface : IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "MouseHighlighter";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.MouseHighlighter;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredMouseHighlighterEnabledValue();
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
public void Disable()
{
DisableMouseHighlighter();
}
public void Enable()
{
EnableMouseHighlighter();
}
private void InitializeShortcuts()
{
Shortcuts.Clear();
Shortcuts.Add((SettingsUtils.Default.GetSettings<MouseHighlighterSettings>(Name).Properties.ActivationShortcut, ToggleMouseHighlighter));
}
public void OnSettingsChanged()
{
InitializeShortcuts();
MouseHighlighterSettingsChanged();
}
[LibraryImport("PowerToys.MouseHighlighter.dll")]
internal static partial void DisableMouseHighlighter();
[LibraryImport("PowerToys.MouseHighlighter.dll")]
internal static partial void EnableMouseHighlighter();
[LibraryImport("PowerToys.MouseHighlighter.dll")]
internal static partial void MouseHighlighterSettingsChanged();
[LibraryImport("PowerToys.MouseHighlighter.dll")]
internal static partial void ToggleMouseHighlighter();
}
}

View File

@@ -1,58 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class MouseJumpModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "MouseJump";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.MouseJump;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredMouseJumpEnabledValue();
public override string ProcessPath => "PowerToys.MouseJumpUI.exe";
public override string ProcessName => "PowerToys.MouseJumpUI";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument;
public void Disable()
{
using var terminateEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset, Constants.TerminateMouseJumpSharedEvent());
terminateEvent.Set();
}
public void Enable()
{
PopulateShortcuts();
}
public void OnSettingsChanged()
{
PopulateShortcuts();
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
public void PopulateShortcuts()
{
Shortcuts.Clear();
var settings = SettingsUtils.Default.GetSettings<MouseJumpSettings>(Name);
Shortcuts.Add((settings.Properties.ActivationShortcut, () =>
{
EnsureLaunched();
using var invokeMouseJumpEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset, Constants.MouseJumpShowPreviewEvent());
invokeMouseJumpEvent.Set();
}));
}
}
}

View File

@@ -1,65 +0,0 @@
// 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.Runtime.InteropServices;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed partial class MousePointerCrosshairsModuleInterface : IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "MousePointerCrosshairs";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.MousePointerCrosshairs;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue();
public void Disable()
{
DisableMousePointerCrosshairs();
}
public void Enable()
{
InitializeShortcuts();
EnableMousePointerCrosshairs();
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
private void InitializeShortcuts()
{
Shortcuts.Clear();
var settings = SettingsUtils.Default.GetSettings<MousePointerCrosshairsSettings>(Name).Properties;
Shortcuts.Add((settings.ActivationShortcut, OnMousePointerCrosshairsActivationShortcut));
Shortcuts.Add((settings.GlidingCursorActivationShortcut, OnMousePointerCrosshairsGlidingCursorShortcut));
}
public void OnSettingsChanged()
{
OnMousePointerCrosshairsSettingsChanged();
InitializeShortcuts();
}
[LibraryImport("PowerToys.MousePointerCrosshairs.dll")]
internal static partial void DisableMousePointerCrosshairs();
[LibraryImport("PowerToys.MousePointerCrosshairs.dll")]
internal static partial void EnableMousePointerCrosshairs();
[LibraryImport("PowerToys.MousePointerCrosshairs.dll")]
internal static partial void OnMousePointerCrosshairsSettingsChanged();
[LibraryImport("PowerToys.MousePointerCrosshairs.dll")]
internal static partial void OnMousePointerCrosshairsActivationShortcut();
[LibraryImport("PowerToys.MousePointerCrosshairs.dll")]
internal static partial void OnMousePointerCrosshairsGlidingCursorShortcut();
}
}

View File

@@ -1,33 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class PowerAccentModuleInterface : ProcessModuleAbstractClass, IPowerToysModule
{
public string Name => "PowerAccent";
public bool Enabled => SettingsUtils.Default.GetSettingsOrDefault<GeneralSettings>().Enabled.PowerAccent;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredQuickAccentEnabledValue();
public override string ProcessPath => "PowerToys.PowerAccent.exe";
public override string ProcessName => "PowerToys.PowerAccent";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument;
public void Disable()
{
}
public void Enable()
{
}
}
}

View File

@@ -1,59 +0,0 @@
// 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.Text.Json;
using System.Threading;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class PowerOCRModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "TextExtractor";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.PowerOcr;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredTextExtractorEnabledValue();
public override string ProcessPath => "PowerToys.PowerOCR.exe";
public override string ProcessName => "PowerToys.PowerOCR";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument;
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
private void PopulateShortcuts()
{
Shortcuts.Clear();
Shortcuts.Add((SettingsUtils.Default.GetSettings<PowerOcrSettings>(Name).Properties.ActivationShortcut, () =>
{
using var invokeOcrEvent = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent());
invokeOcrEvent.Set();
}
));
}
public void Disable()
{
using var terminateEvent = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.TerminatePowerOCRSharedEvent());
terminateEvent.Set();
}
public void Enable()
{
PopulateShortcuts();
}
public void OnSettingsChanged()
{
PopulateShortcuts();
}
}
}

View File

@@ -1,54 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class PowerToysRunModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleShortcutsProvider
{
public string Name => "PowerToys Run";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.PowerLauncher;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredPowerLauncherEnabledValue();
public override string ProcessPath => Path.GetFullPath("PowerToys.PowerLauncher.exe");
public override string ProcessName => "PowerToys.PowerLauncher";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.ElevateIfApplicable | ProcessLaunchOptions.SingletonProcess;
public override string ProcessArguments => $"-powerToysPid {Environment.ProcessId}";
public void Disable()
{
using var terminateEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset, Constants.RunExitEvent());
terminateEvent.Set();
}
public void Enable()
{
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts =>
[
(
SettingsUtils.Default.GetSettings<PowerLauncherSettings>(Name).Properties.OpenPowerLauncher,
() =>
{
EnsureLaunched();
using var invokeRunEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset, Constants.PowerLauncherCentralizedHookSharedEvent());
invokeRunEvent.Set();
}
),
];
}
}

View File

@@ -1,142 +0,0 @@
// 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.Reflection;
using System.Text.Json;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.Win32;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class RegistryPreviewModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleCustomActionsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public bool Enabled => SettingsUtils.Default.GetSettingsOrDefault<GeneralSettings>().Enabled.RegistryPreview;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredHostsFileEditorEnabledValue();
public string Name => "RegistryPreview";
public override string ProcessPath => "WinUI3Apps\\PowerToys.RegistryPreview.exe";
public override string ProcessName => "PowerToys.RegistryPreview";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SupressLaunchOnModuleEnabled | ProcessLaunchOptions.NeverExit;
public void Disable()
{
if (!RegistryPreviewChangeSet.UnApplyIfApplied())
{
Logger.LogError("Unapplying registry changes failed");
}
}
public void OnSettingsChanged()
{
bool defaultRegApp = SettingsUtils.Default.GetSettings<RegistryPreviewSettings>(Name).Properties.DefaultRegApp;
if (defaultRegApp && !RegistryPreviewSetDefaultAppChangeSet.IsApplied)
{
if (!RegistryPreviewSetDefaultAppChangeSet.Apply())
{
Logger.LogError("Applying reg default handler failed.");
}
NativeMethods.SHChangeNotify(NativeMethods.SHCNE_ASSOCCHANGED, NativeMethods.SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);
}
else if (!defaultRegApp && RegistryPreviewSetDefaultAppChangeSet.IsApplied)
{
if (RegistryPreviewSetDefaultAppChangeSet.UnApply())
{
Logger.LogError("Unapplying reg default handler failed.");
}
NativeMethods.SHChangeNotify(NativeMethods.SHCNE_ASSOCCHANGED, NativeMethods.SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);
}
}
public void Enable()
{
if (!RegistryPreviewChangeSet.ApplyIfNotApplied())
{
Logger.LogError("Applying registry changes failed");
}
OnSettingsChanged();
}
public Dictionary<string, Action> CustomActions
{
get => new() { { "Launch", () => LaunchProcess() } };
}
private RegistryChangeSet RegistryPreviewSetDefaultAppChangeSet
{
get
{
string installationDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
string appName = "Registry Preview";
string registryKeyPrefix = "Software\\Classes\\";
RegistryValueChange[] changes =
[
new RegistryValueChange
{
KeyPath = registryKeyPrefix + ProcessName + "\\Application",
KeyName = "ApplicationName",
Value = appName,
},
new RegistryValueChange
{
KeyPath = registryKeyPrefix + ProcessName + "\\DefaultIcon",
KeyName = null,
Value = installationDir + "\\WinUI3Apps\\PowerToys.RegistryPreview.exe",
},
new RegistryValueChange
{
KeyPath = registryKeyPrefix + ProcessName + "\\shell\\open\\command",
KeyName = null,
Value = installationDir + "\\WinUI3Apps\\PowerToys.RegistryPreview.exe \"----ms-protocol:ms-encodedlaunch:App?ContractId=Windows.File&Verb=open&File=%1\"",
},
new RegistryValueChange
{
KeyPath = registryKeyPrefix + ".reg\\OpenWithProgIDs",
KeyName = null,
Value = ProcessName,
}
];
return new RegistryChangeSet { Changes = changes };
}
}
private RegistryChangeSet RegistryPreviewChangeSet
{
get
{
string installationDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
RegistryValueChange[] changes =
[
new RegistryValueChange
{
KeyPath = "Software\\Classes\\regfile\\shell\\preview\\command",
KeyName = null,
Value = installationDir + "\\WinUI3Apps\\PowerToys.RegistryPreview.exe \"%1\"",
},
new RegistryValueChange
{
KeyPath = "Software\\Classes\\regfile\\shell\\preview",
KeyName = "icon",
Value = installationDir + "\\WinUI3Apps\\Assets\\RegistryPreview\\RegistryPreview.ico",
}
];
return new RegistryChangeSet() { Changes = changes };
}
}
}
}

View File

@@ -1,52 +0,0 @@
// 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 Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class WorkspacesModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleShortcutsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "Workspaces";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.Workspaces;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredWorkspacesEnabledValue();
public override string ProcessPath => "PowerToys.WorkspacesEditor.exe";
public override string ProcessName => "PowerToys.WorkspacesEditor";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SupressLaunchOnModuleEnabled | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument;
public void Disable()
{
}
public void Enable()
{
InitializeShortcuts();
}
public void OnSettingsChanged()
{
InitializeShortcuts();
}
private void InitializeShortcuts()
{
Shortcuts.Clear();
Shortcuts.Add((SettingsUtils.Default.GetSettings<WorkspacesSettings>(Name).Properties.Hotkey, () =>
{
LaunchProcess();
}));
}
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];
}
}

View File

@@ -1,45 +0,0 @@
// 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.Threading;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapper;
using PowerToys.Interop;
using RunnerV2.Models;
namespace RunnerV2.ModuleInterfaces
{
internal sealed class ZoomItModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IPowerToysModuleCustomActionsProvider, IPowerToysModuleSettingsChangedSubscriber
{
public string Name => "ZoomIt";
public bool Enabled => SettingsUtils.Default.GetSettings<GeneralSettings>().Enabled.ZoomIt;
public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredZoomItEnabledValue();
public override string ProcessPath => "PowerToys.ZoomIt.exe";
public override string ProcessName => "PowerToys.ZoomIt";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument;
public void Disable()
{
}
public void Enable()
{
}
public Dictionary<string, Action> CustomActions { get => new() { { "refresh_settings", () => OnSettingsChanged() } }; }
public void OnSettingsChanged()
{
using var refreshSettingsEvent = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ZoomItRefreshSettingsEvent());
refreshSettingsEvent.Set();
}
}
}

View File

@@ -1,246 +0,0 @@
// 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.Drawing;
using System.Runtime.InteropServices;
using ManagedCommon;
using Windows.ApplicationModel;
namespace RunnerV2
{
internal static partial class NativeMethods
{
[LibraryImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool OpenProcessToken(IntPtr processHandle, uint desiredAccess, out IntPtr tokenHandle);
[LibraryImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool GetTokenInformation(IntPtr tokenHandle, TOKEN_INFORMATION_CLASS tokenInformationClass, ref TokenElevation tokenInformation, uint tokenInformationLength, out uint returnLength);
[LibraryImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool CloseHandle(IntPtr hObject);
internal enum TOKEN_INFORMATION_CLASS
{
TOKEN_ELEVATION = 20,
}
[StructLayout(LayoutKind.Sequential)]
internal struct TokenElevation
{
public uint TokenIsElevated;
}
internal const int TOKENQUERY = 0x0008;
[LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool UnregisterHotKey(IntPtr hWnd, int id);
[LibraryImport("user32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool AppendMenuW(IntPtr hMenu, uint uFlags, UIntPtr uIDNewItem, string lpNewItem);
[LibraryImport("user32.dll", SetLastError = true)]
internal static partial IntPtr CreatePopupMenu();
[LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool SetForegroundWindow(IntPtr hWnd);
[LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool TrackPopupMenu(IntPtr hMenu, uint uFlags, int x, int y, int nReserved, IntPtr hWnd, IntPtr prcRect);
[LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
internal const uint NIMADD = 0x00000000;
internal const uint NIMDELETE = 0x00000002;
internal struct NOTIFYICONDATA
{
public uint CbSize;
public IntPtr HWnd;
public uint UId;
public uint UFlags;
public uint UCallbackMessage;
public IntPtr HIcon;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string SzTip;
public uint DwState;
public uint DwStateMask;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string SzInfo;
public uint UTimeoutOrVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string SzInfoTitle;
public uint DwInfoFlags;
public Guid GuidItem;
public IntPtr HBalloonIcon;
}
[DllImport("shell32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool Shell_NotifyIcon(uint dwMessage, ref NOTIFYICONDATA lpdata);
[LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, uint action, IntPtr pChangeFilterStruct);
internal const uint CSVREDRAW = 0x0001;
internal const uint CSHREDRAW = 0x0002;
internal const uint WSOVERLAPPEDWINDOW = 0x00CF0000;
internal const uint WSPOPUP = 0x80000000;
internal const int CWUSEDEFAULT = unchecked((int)0x80000000);
internal static readonly IntPtr IDCARROW = new(32512);
[DllImport("user32.dll")]
internal static extern IntPtr GetMessageW(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool TranslateMessage(ref MSG lpMsg);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DispatchMessageW(ref MSG lpMsg);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool PostMessageW(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[LibraryImport("kernel32.dll")]
internal static partial ushort AddAtomW([MarshalAs(UnmanagedType.LPWStr)] string lpString);
internal struct MSG
{
public IntPtr HWnd;
public uint Message;
public UIntPtr WParam;
public long LParam;
public ulong Time;
public Point Pt;
}
internal enum WindowMessages : uint
{
COMMAND = 0x0111,
HOTKEY = 0x0312,
ICON_NOTIFY = 0x0800,
WINDOWPOSCHANGING = 0x0046,
DESTROY = 0x0002,
REFRESH_SETTINGS = 0x0400 + 2,
}
[DllImport("user32.dll")]
internal static extern ushort RegisterClassW(ref WNDCLASS lpWndClass);
[LibraryImport("user32.dll", SetLastError = false)]
internal static partial IntPtr DefWindowProcW(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[LibraryImport("user32.dll", SetLastError = true)]
internal static partial uint RegisterWindowMessageW([MarshalAs(UnmanagedType.LPWStr)] string lpString);
[LibraryImport("user32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
internal static partial nint CreateWindowExW(
uint dwExStyle,
string lpClassName,
string lpWindowName,
uint dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct WNDCLASS
{
public uint Style;
public WndProc LpfnWndProc;
public int CbClsExtra;
public int CbWndExtra;
public IntPtr HInstance;
public IntPtr HIcon;
public IntPtr HCursor;
public IntPtr HbrBackground;
[MarshalAs(UnmanagedType.LPWStr)]
public string LpszMenuName;
[MarshalAs(UnmanagedType.LPWStr)]
public string LpszClassName;
}
[DllImport("Advapi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ConvertStringSecurityDescriptorToSecurityDescriptorW(
[MarshalAs(UnmanagedType.LPWStr)] string StringSecurityDescriptor,
uint StringSDRevision,
out IntPtr SecurityDescriptor,
out uint SecurityDescriptorSize);
[DllImport("Advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool MakeAbsoluteSD(
IntPtr pSelfRelativeSD,
IntPtr pAbsoluteSD,
ref uint lpdwAbsoluteSDSize,
IntPtr pDacl,
ref uint lpdwDaclSize,
IntPtr pSacl,
ref uint lpdwSaclSize,
IntPtr pOwner,
ref uint lpdwOwnerSize,
IntPtr pPrimaryGroup,
ref uint lpdwPrimaryGroupSize);
[DllImport("ole32.dll", SetLastError = true)]
internal static extern int CoInitializeSecurity(
IntPtr pSecDesc,
int cAuthSvc,
IntPtr asAuthSvc,
IntPtr pReserved1,
uint dwAuthnLevel,
uint dwImpLevel,
IntPtr pAuthList,
uint dwCapabilities,
IntPtr pReserved3);
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, NativeKeyboardHelper.INPUT[] pInputs, int cbSize);
[DllImport("PowerToys.Interop.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool GetPackageNameAndVersionFromAppx(
[MarshalAs(UnmanagedType.LPWStr)] string appxPath,
[MarshalAs(UnmanagedType.LPWStr)] out string outName,
out PackageVersion outVersion);
[LibraryImport("Shell32.dll", SetLastError = true)]
internal static partial void SHChangeNotify(
uint wEventId,
uint uFlags,
IntPtr dwItem1,
IntPtr dwItem2);
internal const uint SHCNE_ASSOCCHANGED = 0x8000000;
internal const uint SHCNF_IDLIST = 0x0;
}
}

View File

@@ -1,165 +0,0 @@
// 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.Diagnostics;
using System.Linq;
using System.Reflection;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.GPOWrapperProjection;
using RunnerV2;
using RunnerV2.Helpers;
using RunnerV2.Models;
using Settings.UI.Library;
internal sealed class Program
{
private static readonly SettingsUtils _settingsUtils = SettingsUtils.Default;
internal static GeneralSettings GeneralSettings => _settingsUtils.GetSettings<GeneralSettings>();
private static void Main(string[] args)
{
Logger.InitializeLogger("\\RunnerLogs");
string securityDescriptor =
"O:BA" // Owner: Builtin (local) administrator
+ "G:BA" // Group: Builtin (local) administrator
+ "D:"
+ "(A;;0x7;;;PS)" // Access allowed on COM_RIGHTS_EXECUTE, _LOCAL, & _REMOTE for Personal self
+ "(A;;0x7;;;IU)" // Access allowed on COM_RIGHTS_EXECUTE for Interactive Users
+ "(A;;0x3;;;SY)" // Access allowed on COM_RIGHTS_EXECUTE, & _LOCAL for Local system
+ "(A;;0x7;;;BA)" // Access allowed on COM_RIGHTS_EXECUTE, _LOCAL, & _REMOTE for Builtin (local) administrator
+ "(A;;0x3;;;S-1-15-3-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646)" // Access allowed on COM_RIGHTS_EXECUTE, & _LOCAL for Win32WebViewHost package capability
+ "S:"
+ "(ML;;NX;;;LW)"; // Integrity label on No execute up for Low mandatory level
COMUtils.InitializeCOMSecurity(securityDescriptor);
switch (ShouldRunInSpecialMode(args))
{
case SpecialMode.None:
break;
case SpecialMode.UpdateNow:
UpdateNow();
return;
case SpecialMode.DisableCantDragElevatedNotification:
Environment.Exit(NotificationHelper.DisableToast(NotificationHelper.ToastType.ElevatedDontShowAgain) ? 1 : 0);
return;
case SpecialMode.CouldntToggleFileExplorerModulesNotification:
Environment.Exit(NotificationHelper.DisableToast(NotificationHelper.ToastType.CouldntToggleFileExplorerModules) ? 1 : 0);
return;
default:
throw new NotImplementedException("Special modes are not implemented yet.");
}
bool shouldOpenSettings = args.Any(s => s.StartsWith("--open-settings", StringComparison.InvariantCulture));
bool shouldOpenSettingsToSpecificPage = args.Any(s => s.StartsWith("--open-settings=", StringComparison.InvariantCulture));
// Check if PowerToys is already running
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
throw new NotImplementedException("Opening another instance window is not supported yet.");
}
/*
* Todo: Data diagnotics
*/
bool isElevated = ElevationHelper.IsProcessElevated();
bool hasDontElevateArgument = args.Contains("--dont-elevate");
bool runElevatedSetting = GeneralSettings.RunElevated;
bool hasRestartedElevatedArgment = args.Contains("--restartedElevated");
Action afterInitializationAction = () => { };
Version version = Assembly.GetExecutingAssembly().GetName().Version!;
if ($"v{version.Major}.{version.Minor}.{version.Build}" != _settingsUtils.GetSettings<LastVersionRunSettings>(fileName: "last_version_run.json").LastVersion && (!GeneralSettings.ShowWhatsNewAfterUpdates || GPOWrapper.GetDisableShowWhatsNewAfterUpdatesValue() != GpoRuleConfigured.Disabled))
{
afterInitializationAction += () =>
{
SettingsHelper.OpenSettingsWindow(showScoobeWindow: true);
};
}
if (!_settingsUtils.GetSettings<OOBESettings>(fileName: "oobe_settings.json").OpenedAtFirstLaunch)
{
afterInitializationAction += () =>
{
SettingsHelper.OpenSettingsWindow(showOobeWindow: true);
};
}
if (shouldOpenSettings)
{
afterInitializationAction += () =>
{
SettingsHelper.OpenSettingsWindow(additionalArguments: shouldOpenSettingsToSpecificPage ? args.First(s => s.StartsWith("--open-settings=", StringComparison.InvariantCulture)).Replace("--open-settings=", string.Empty, StringComparison.InvariantCulture) : null);
};
}
// Set last version run
_settingsUtils.SaveSettings(new LastVersionRunSettings() { LastVersion = $"v{version.Major}.{version.Minor}.{version.Build}" }.ToJsonString(), fileName: "last_version_run.json");
switch ((isElevated, hasDontElevateArgument, runElevatedSetting, hasRestartedElevatedArgment))
{
case (true, true, false, _):
// Todo: Scheudle restart as non elevated
throw new NotImplementedException();
case (true, _, _, _):
case (_, _, false, _):
case (_, true, _, _):
case (false, _, _, true):
GeneralSettings tempGeneralSettings = GeneralSettings;
tempGeneralSettings.IsElevated = isElevated;
_settingsUtils.SaveSettings(tempGeneralSettings.ToJsonString());
Runner.Run(afterInitializationAction);
break;
default:
ElevationHelper.RestartScheduled = ElevationHelper.RestartScheduledMode.RestartElevated;
break;
}
ElevationHelper.RestartIfScheudled();
}
/// <summary>
/// Returns whether the application should run in a special mode based on the provided arguments.
/// </summary>
/// <param name="args">The arguments passed to <see cref="Main(string[])"/></param>
/// <returns>The <see cref="SpecialMode"/> the app should run in.</returns>
private static SpecialMode ShouldRunInSpecialMode(string[] args)
{
if (args.Length > 0 && args[0].StartsWith("powertoys://", StringComparison.InvariantCultureIgnoreCase))
{
Uri uri = new(args[0]);
string host = uri.Host.ToLowerInvariant();
return host switch
{
"update_now" => SpecialMode.UpdateNow,
"cant_drag_elevated_disable" => SpecialMode.DisableCantDragElevatedNotification,
"couldnt_toggle_powerpreview_modules_disable" => SpecialMode.CouldntToggleFileExplorerModulesNotification,
_ => SpecialMode.None,
};
}
return SpecialMode.None;
}
/// <summary>
/// Starts the update process for PowerToys.
/// </summary>
private static void UpdateNow()
{
Process.Start(new ProcessStartInfo()
{
UseShellExecute = false,
CreateNoWindow = true,
FileName = "PowerToys.Update.exe",
Arguments = "-update_now",
});
}
}

View File

@@ -1,313 +0,0 @@
// 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.Frozen;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
using ManagedCommon;
using RunnerV2.Helpers;
using RunnerV2.Models;
using RunnerV2.ModuleInterfaces;
using Update;
using static RunnerV2.NativeMethods;
namespace RunnerV2
{
internal static partial class Runner
{
/// <summary>
/// Gets the window handle for the Runner main window that hosts the tray icon and receives system messages.
/// </summary>
public static nint RunnerHwnd { get; private set; }
private const string TrayWindowClassName = "pt_tray_icon_window_class";
/// <summary>
/// Gets all the currently loaded modules.
/// </summary>
public static List<IPowerToysModule> LoadedModules { get; } = [];
private static List<IPowerToysModule> _failedModuleLoads = [];
/// <summary>
/// Gets the list of all available PowerToys modules.
/// </summary>
public static FrozenSet<IPowerToysModule> ModulesToLoad { get; } =
[
new ColorPickerModuleInterface(),
new AlwaysOnTopModuleInterface(),
new HostsModuleInterface(),
new PowerAccentModuleInterface(),
new AdvancedPasteModuleInterface(),
new AwakeModuleInterface(),
new CmdNotFoundModuleInterface(),
new CommandPaletteModuleInterface(),
new CropAndLockModuleInterface(),
new EnvironmentVariablesModuleInterface(),
new RegistryPreviewModuleInterface(),
new FileExplorerModuleInterface(),
new ZoomItModuleInterface(),
new PowerOCRModuleInterface(),
new MeasureToolModuleInterface(),
new MouseJumpModuleInterface(),
new FancyZonesModuleInterface(),
new PowerToysRunModuleInterface(),
new KeyboardManagerModuleInterface(),
new LightSwitchModuleInterface(),
new CursorWrapModuleInterface(),
new FindMyMouseModuleInterface(),
new WorkspacesModuleInterface(),
new MousePointerCrosshairsModuleInterface(),
new MouseHighlighterModuleInterface(),
];
/// <summary>
/// Runs the main message loop for Runner.
/// </summary>
/// <param name="afterInitializationAction">A function to execute after initialization.</param>
internal static void Run(Action afterInitializationAction)
{
Logger.LogInfo("Runner started");
InitializeTrayWindow();
TrayIconManager.StartTrayIcon();
Task.Run(UpdateUtilities.UninstallPreviousMsixVersions);
foreach (IPowerToysModule module in ModulesToLoad)
{
ToggleModuleStateBasedOnEnabledProperty(module);
}
CentralizedKeyboardHookManager.Start();
afterInitializationAction();
MessageLoop();
}
private static readonly uint _taskbarCreatedMessage = RegisterWindowMessageW("TaskbarCreated");
/// <summary>
/// The main message loop that processes Windows messages.
/// </summary>
[STAThread]
private static void MessageLoop()
{
while (GetMessageW(out MSG msg, IntPtr.Zero, 0, 0) != 0 || true)
{
TranslateMessage(ref msg);
DispatchMessageW(ref msg);
// Supress duplicate handling of HOTKEY messages
if (msg.Message == (uint)WindowMessages.HOTKEY)
{
continue;
}
HandleMessage(msg.HWnd, msg.Message, (nint)msg.WParam, (nint)msg.LParam);
}
Close();
}
/// <summary>
/// Closes Runner and all loaded modules.
/// </summary>
[DoesNotReturn]
internal static void Close()
{
TrayIconManager.StopTrayIcon();
SettingsHelper.CloseSettingsWindow();
ElevationHelper.RestartIfScheudled();
foreach (IPowerToysModule module in LoadedModules)
{
try
{
module.Disable();
if (module is ProcessModuleAbstractClass pmac)
{
pmac.ProcessExit();
}
}
catch (Exception e)
{
MessageBox.Show($"The module {module.Name} failed to unload: \n" + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Environment.Exit(0);
}
/// <summary>
/// Toggles the state of a module based on its enabled property and GPO rules.
/// </summary>
/// <param name="module">The module to toggle</param>
public static void ToggleModuleStateBasedOnEnabledProperty(IPowerToysModule module)
{
if (_failedModuleLoads.Contains(module))
{
return;
}
try
{
if ((module.Enabled && (module.GpoRuleConfigured != PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)) || module.GpoRuleConfigured == PowerToys.GPOWrapper.GpoRuleConfigured.Enabled)
{
/* Todo: conflict manager */
if (!LoadedModules.Contains(module))
{
module.Enable();
if (module is ProcessModuleAbstractClass pmac)
{
pmac.LaunchProcess(true);
}
LoadedModules.Add(module);
}
CentralizedKeyboardHookManager.RemoveAllHooksFromModule(module.Name);
if (module is IPowerToysModuleShortcutsProvider shortcutsProvider)
{
foreach (var shortcut in shortcutsProvider.Shortcuts.ToArray())
{
CentralizedKeyboardHookManager.AddKeyboardHook(module.Name, shortcut.Hotkey, shortcut.Action);
}
}
return;
}
}
catch (IOException)
{
return;
}
catch (Exception e)
{
MessageBox.Show($"The module {module.Name} failed to load: \n" + e.Message, "Error: " + e.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
_failedModuleLoads.Add(module);
return;
}
try
{
module.Disable();
if (module is ProcessModuleAbstractClass pmac)
{
pmac.ProcessExit();
}
CentralizedKeyboardHookManager.RemoveAllHooksFromModule(module.Name);
LoadedModules.Remove(module);
}
catch (IOException)
{
}
catch (Exception e)
{
MessageBox.Show($"The module {module.Name} failed to unload: \n" + e.Message, "Error: " + e.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
_failedModuleLoads.Add(module);
}
}
/// <summary>
/// Initializes the tray window to receive system messages.
/// </summary>
[STAThread]
private static void InitializeTrayWindow()
{
IntPtr hInstance = Process.GetCurrentProcess().MainModule!.BaseAddress;
IntPtr hCursor = Cursors.Arrow.Handle;
IntPtr hIcon = SystemIcons.Application.Handle;
var wc = new WNDCLASS
{
HCursor = hCursor,
HInstance = hInstance,
LpszClassName = TrayWindowClassName,
Style = CSHREDRAW | CSVREDRAW,
LpfnWndProc = HandleMessage,
HIcon = hIcon,
HbrBackground = IntPtr.Zero,
LpszMenuName = string.Empty,
CbClsExtra = 0,
CbWndExtra = 0,
};
_ = RegisterClassW(ref wc);
RunnerHwnd = CreateWindowExW(
0,
wc.LpszClassName,
TrayWindowClassName,
WSOVERLAPPEDWINDOW | WSPOPUP,
CWUSEDEFAULT,
CWUSEDEFAULT,
CWUSEDEFAULT,
CWUSEDEFAULT,
IntPtr.Zero,
IntPtr.Zero,
wc.HInstance,
IntPtr.Zero);
if (RunnerHwnd == IntPtr.Zero)
{
var err = Marshal.GetLastPInvokeError();
MessageBox.Show($"CreateWindowExW failed. LastError={err}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// Handles Windows messages sent to the tray window.
/// </summary>
private static IntPtr HandleMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
switch (msg)
{
case (uint)WindowMessages.ICON_NOTIFY:
TrayIconManager.ProcessTrayIconMessage(lParam);
break;
case (uint)WindowMessages.COMMAND:
TrayIconManager.ProcessTrayMenuCommand((nuint)wParam);
break;
case (uint)WindowMessages.WINDOWPOSCHANGING:
TrayIconManager.StartTrayIcon();
break;
case (uint)WindowMessages.DESTROY:
Close();
break;
case (uint)WindowMessages.REFRESH_SETTINGS:
foreach (IPowerToysModule module in ModulesToLoad)
{
ToggleModuleStateBasedOnEnabledProperty(module);
}
break;
default:
if (msg == _taskbarCreatedMessage)
{
TrayIconManager.StartTrayIcon();
}
break;
}
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
}
}

View File

@@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\Common.SelfContained.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<Description>PowerToys Runner</Description>
<AssemblyName>PowerToys</AssemblyName>
<OutputPath>..\..\..\$(Platform)\$(Configuration)</OutputPath>
<Nullable>enable</Nullable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<ApplicationIcon>icon.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\GPOWrapperProjection\GPOWrapperProjection.csproj" />
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\common\ManagedCsWin32\ManagedCsWin32.csproj" />
<ProjectReference Include="..\..\modules\poweraccent\PowerAccent.UI\PowerAccent.UI.csproj" />
<ProjectReference Include="..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\..\Update\Update.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -0,0 +1,36 @@
#include <windows.h>
#include "resource.h"
#include "../common/version/version.h"
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
END
END

View File

@@ -0,0 +1,234 @@
// 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.
#define WIN32_LEAN_AND_MEAN
#include "Generated Files/resource.h"
#include <Windows.h>
#include <shellapi.h>
#include <filesystem>
#include <string_view>
#include <common/updating/updating.h>
#include <common/updating/updateState.h>
#include <common/updating/installer.h>
#include <common/utils/elevation.h>
#include <common/utils/HttpClient.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include <common/utils/timeutil.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/logger/logger.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Storage.h>
#include <Msi.h>
#include "../runner/tray_icon.h"
#include "../runner/UpdateUtils.h"
using namespace cmdArg;
namespace fs = std::filesystem;
std::optional<fs::path> CopySelfToTempDir()
{
std::error_code error;
auto dst_path = fs::temp_directory_path() / "PowerToys.Update.exe";
fs::copy_file(get_module_filename(), dst_path, fs::copy_options::overwrite_existing, error);
if (error)
{
return std::nullopt;
}
return std::move(dst_path);
}
std::optional<fs::path> ObtainInstaller(bool& isUpToDate)
{
using namespace updating;
isUpToDate = false;
auto state = UpdateState::read();
const auto new_version_info = get_github_version_info_async().get();
if (std::holds_alternative<version_up_to_date>(*new_version_info))
{
isUpToDate = true;
Logger::error("Invoked with -update_now argument, but no update was available");
return std::nullopt;
}
if (state.state == UpdateState::readyToDownload || state.state == UpdateState::errorDownloading)
{
if (!new_version_info)
{
Logger::error(L"Couldn't obtain github version info: {}", new_version_info.error());
return std::nullopt;
}
// Cleanup old updates before downloading the latest
updating::cleanup_updates();
auto downloaded_installer = download_new_version(std::get<new_version_download_info>(*new_version_info)).get();
if (!downloaded_installer)
{
Logger::error("Couldn't download new installer");
}
return downloaded_installer;
}
else if (state.state == UpdateState::readyToInstall)
{
fs::path installer{ get_pending_updates_path() / state.downloadedInstallerFilename };
if (fs::is_regular_file(installer))
{
return std::move(installer);
}
else
{
Logger::error(L"Couldn't find a downloaded installer {}", installer.native());
return std::nullopt;
}
}
else if (state.state == UpdateState::upToDate)
{
isUpToDate = true;
return std::nullopt;
}
Logger::error("Invoked with -update_now argument, but update state was invalid");
return std::nullopt;
}
bool InstallNewVersionStage1(fs::path installer)
{
if (auto copy_in_temp = CopySelfToTempDir())
{
// Detect if PT was running
const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, nullptr);
if (pt_main_window != nullptr)
{
SendMessageW(pt_main_window, WM_CLOSE, 0, 0);
}
std::wstring arguments{ UPDATE_NOW_LAUNCH_STAGE2 };
arguments += L" \"";
arguments += installer.c_str();
arguments += L"\"";
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
sei.lpFile = copy_in_temp->c_str();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = arguments.c_str();
return ShellExecuteExW(&sei) == TRUE;
}
else
{
return false;
}
}
bool InstallNewVersionStage2(std::wstring installer_path)
{
std::transform(begin(installer_path), end(installer_path), begin(installer_path), ::towlower);
bool success = true;
if (installer_path.ends_with(L".msi"))
{
success = MsiInstallProductW(installer_path.data(), nullptr) == ERROR_SUCCESS;
}
else
{
// If it's not .msi, then it's a wix bootstrapper
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE };
sei.lpFile = installer_path.c_str();
sei.nShow = SW_SHOWNORMAL;
std::wstring parameters = L"/passive /norestart";
sei.lpParameters = parameters.c_str();
success = ShellExecuteExW(&sei) == TRUE;
// Wait for the install completion
if (success)
{
WaitForSingleObject(sei.hProcess, INFINITE);
DWORD exitCode = 0;
GetExitCodeProcess(sei.hProcess, &exitCode);
success = exitCode == 0;
CloseHandle(sei.hProcess);
}
}
if (!success)
{
return false;
}
UpdateState::store([&](UpdateState& state) {
state = {};
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
state.state = UpdateState::upToDate;
});
return true;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
int nArgs = 0;
LPWSTR* args = CommandLineToArgvW(GetCommandLineW(), &nArgs);
if (!args || nArgs < 2)
{
return 1;
}
std::wstring_view action{ args[1] };
std::filesystem::path logFilePath(PTSettingsHelper::get_root_save_folder_location());
logFilePath.append(LogSettings::updateLogPath);
Logger::init(LogSettings::updateLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
if (action == UPDATE_NOW_LAUNCH_STAGE1)
{
bool isUpToDate = false;
auto installerPath = ObtainInstaller(isUpToDate);
bool failed = !installerPath.has_value();
failed = failed || !InstallNewVersionStage1(std::move(*installerPath));
if (failed)
{
UpdateState::store([&](UpdateState& state) {
state = {};
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
state.state = isUpToDate ? UpdateState::upToDate : UpdateState::errorDownloading;
});
}
return failed;
}
else if (action == UPDATE_NOW_LAUNCH_STAGE2)
{
using namespace std::string_view_literals;
const bool failed = !InstallNewVersionStage2(args[2]);
if (failed)
{
UpdateState::store([&](UpdateState& state) {
state = {};
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
state.state = UpdateState::errorDownloading;
});
}
return failed;
}
return 0;
}

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h PowerToys.Update.base.rc PowerToys.Update.rc" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}</ProjectGuid>
<RootNamespace>Update</RootNamespace>
<ProjectName>PowerToys.Update</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
</PropertyGroup>
<Import Project="..\..\deps\expected.props" />
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup>
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="PowerToys.Update.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\common\notifications\notifications.vcxproj">
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
</ProjectReference>
<ProjectReference Include="..\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\common\updating\updating.vcxproj">
<Project>{17da04df-e393-4397-9cf0-84dabe11032e}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<None Include="PowerToys.Update.base.rc" />
<ResourceCompile Include="Generated Files\PowerToys.Update.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

View File

@@ -1,183 +0,0 @@
// 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.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Update;
[SupportedOSPlatform("windows")]
internal sealed partial class Program
{
private static readonly string _installerPath = Path.Combine(Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft",
"PowerToys",
"Updates"));
private static async Task Main(string[] args)
{
if (args.Length < 1)
{
Environment.Exit(1);
return;
}
string action = args[0];
switch (action)
{
case UpdateStage.UPDATENOWLAUNCHSTAGE1:
await PerformUpdateNowStage1();
break;
case UpdateStage.UPDATENOWLAUNCHSTAGE2:
if (args.Length < 2)
{
Environment.Exit(1);
}
await PerformUpdateNowStage2(args[1]);
break;
default:
break;
}
}
private static async Task PerformUpdateNowStage2(string installerPath)
{
Process installerProcess = new()
{
StartInfo = new ProcessStartInfo
{
FileName = installerPath,
Arguments = "/passive /norestart",
UseShellExecute = true,
},
};
installerProcess.Start();
await installerProcess.WaitForExitAsync();
if (installerProcess.ExitCode == 0)
{
UpdateSettingsHelper.ProcessNoUpdateAvailable();
}
else
{
UpdateSettingsHelper.SetUpdateState(UpdatingSettings.UpdatingState.ErrorDownloading);
}
}
private static async Task PerformUpdateNowStage1()
{
UpdateSettingsHelper.TriggerUpdateCheck();
UpdateSettingsHelper.UpdateInfo updateInfo = await UpdateSettingsHelper.GetUpdateAvailableInfo();
if (updateInfo is not UpdateSettingsHelper.UpdateInfo.UpdateAvailable ua)
{
// No update found
Environment.Exit(1);
return;
}
// Copy itsself to the temp folder
File.Copy("PowerToys.Update.exe", Path.Combine(Path.GetTempPath(), "PowerToys.Update.exe"), true);
string? installerFilePath = null;
switch (UpdateSettingsHelper.GetUpdateState())
{
case UpdatingSettings.UpdatingState.ReadyToDownload:
case UpdatingSettings.UpdatingState.ErrorDownloading:
CleanupUpdates();
installerFilePath = await DownloadFile(ua.InstallerDownloadUrl.ToString(), ua.InstallerFilename);
break;
case UpdatingSettings.UpdatingState.ReadyToInstall:
installerFilePath = Path.Combine(_installerPath, ua.InstallerFilename);
if (!File.Exists(installerFilePath))
{
// Installer not found
Environment.Exit(1);
return;
}
break;
case UpdatingSettings.UpdatingState.UpToDate:
Environment.Exit(0);
return;
}
if (installerFilePath == null)
{
UpdateSettingsHelper.SetUpdateState(UpdatingSettings.UpdatingState.ErrorDownloading);
Environment.Exit(1);
return;
}
IntPtr runnerHwnd = FindWindowW("pt_tray_icon_window_class");
if (runnerHwnd != IntPtr.Zero)
{
SendMessageW(runnerHwnd, 0x0010, IntPtr.Zero, IntPtr.Zero); // Send WM_CLOSE
}
string arguments = $"{UpdateStage.UPDATENOWLAUNCHSTAGE2} \"{installerFilePath}\"";
Process.Start(new ProcessStartInfo
{
FileName = Path.Combine(Path.GetTempPath(), "PowerToys.Update.exe"),
Arguments = arguments,
UseShellExecute = true,
CreateNoWindow = true,
WorkingDirectory = Environment.CurrentDirectory,
});
}
private static async Task<string?> DownloadFile(string downloadUri, string downloadFileName)
{
HttpClient httpClient = new();
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("PowerToys Runner"); // GitHub API requires a user-agent
// 3 Attempts to download the file
for (int i = 0; i < 3; i++)
{
try
{
using FileStream fileStream = new(Path.Combine(_installerPath, downloadFileName), FileMode.Create, FileAccess.Write, FileShare.None);
await (await httpClient.GetStreamAsync(downloadUri)).CopyToAsync(fileStream);
return fileStream.Name;
}
catch
{
}
}
return null;
}
private static void CleanupUpdates()
{
if (!Path.Exists(_installerPath))
{
return;
}
foreach (string file in Directory.GetFiles(_installerPath).Where(f => f.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)))
{
File.Delete(file);
}
}
[LibraryImport("user32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
private static partial IntPtr FindWindowW(string lpClassName);
[LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool SendMessageW(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
}

Some files were not shown because too many files have changed in this diff Show More