Compare commits

..

16 Commits

Author SHA1 Message Date
Gordon Lam (SH)
f37754cc61 fix: improve comment wording for spell check 2026-01-27 19:20:57 -08:00
Gordon Lam (SH)
9be06842c1 feat(cmdpal): implement ActionRunner for elevated process execution 2026-01-27 19:10:21 -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
687 changed files with 31499 additions and 7853 deletions

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
@@ -668,13 +672,14 @@ HCRYPTPROV
hcursor
hcwhite
hdc
HDEVNOTIFY
hdr
hdrop
hdwwiz
Helpline
helptext
HGFE
hgdiobj
HGFE
hglobal
hhk
HHmmssfff
@@ -750,9 +755,9 @@ HWNDPARENT
HWNDPREV
hyjiacan
IAI
icf
ICONERROR
ICONLOCATION
icf
IDCANCEL
IDD
idk
@@ -843,8 +848,8 @@ jeli
jfif
jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi
jjw
JOBOBJECT
jobject
JOBOBJECT
jpe
jpnime
Jsons
@@ -888,6 +893,7 @@ Ldr
LEFTALIGN
LEFTSCROLLBAR
LEFTTEXT
leftclick
LError
LEVELID
LExit
@@ -930,9 +936,9 @@ LOWORD
lparam
LPBITMAPINFOHEADER
LPCFHOOKPROC
lpch
LPCITEMIDLIST
LPCLSID
lpch
lpcmi
LPCMINVOKECOMMANDINFO
LPCREATESTRUCT
@@ -948,6 +954,7 @@ LPMONITORINFO
LPOSVERSIONINFOEXW
LPQUERY
lprc
LPrivate
LPSAFEARRAY
lpstr
lpsz
@@ -957,7 +964,6 @@ lptpm
LPTR
LPTSTR
lpv
LPrivate
LPW
lpwcx
lpwndpl
@@ -1001,18 +1007,19 @@ mber
MBM
MBR
Mbuttondown
mcp
MDICHILD
MDL
mdtext
mdtxt
mdwn
meme
mcp
memicmp
MENUITEMINFO
MENUITEMINFOW
MERGECOPY
MERGEPAINT
Metacharacter
metadatamatters
Metadatas
metafile
@@ -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
@@ -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,8 @@ RIGHTSCROLLBAR
riid
RKey
RNumber
rop
rollups
rop
ROUNDSMALL
ROWSETEXT
rpcrt
@@ -1760,15 +1765,13 @@ SUBMODULEUPDATE
subresource
Superbar
sut
swe
svchost
SVGIn
SVGIO
svgz
SVSI
SWFO
SWP
Swp
swp
SWPNOSIZE
SWPNOZORDER
SWRESTORE
@@ -1787,8 +1790,7 @@ SYSKEY
syskeydown
SYSKEYUP
SYSLIB
SYSMENU
Sysmenu
sysmenu
systemai
SYSTEMAPPS
SYSTEMMODAL
@@ -1892,9 +1894,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

@@ -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">

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">
@@ -360,12 +371,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 +396,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 +419,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 +431,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 +457,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 +479,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 +495,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 +665,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 +680,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 +702,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 +774,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 +811,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 +976,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 +1002,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 +1047,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

@@ -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

@@ -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,169 @@
// 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);
}
}
}
else if (action == RUN_AS_USER || action == RUN_AS_ADMIN)
{
// Handle "Run as different user" and "Run as administrator" actions.
// This is used by Command Palette to work around WinUI3/MSIX packaging limitations
// where ShellExecute with "runas user"/"runas" verbs doesn't work properly from packaged apps.
int nextArg = 2;
std::wstring_view target;
std::wstring_view workingDir;
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"-workingDir" && nextArg + 1 < nArgs)
{
workingDir = args[nextArg + 1];
nextArg += 2;
}
else
{
nextArg++;
}
}
if (target.empty())
{
Logger::error(L"ActionRunner: {} called without -target argument", action);
return 1;
}
Logger::trace(L"ActionRunner: {} target='{}' workingDir='{}'", action, target, workingDir);
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.fMask = SEE_MASK_FLAG_NO_UI;
sei.lpFile = target.data();
sei.lpDirectory = workingDir.empty() ? nullptr : workingDir.data();
sei.lpVerb = (action == RUN_AS_ADMIN) ? L"runas" : L"runasuser";
sei.nShow = SW_SHOWNORMAL;
if (!ShellExecuteExW(&sei))
{
DWORD error = GetLastError();
if (error == ERROR_CANCELLED)
{
// User cancelled the UAC/credential dialog - this is expected behavior
Logger::trace(L"ActionRunner: User cancelled {} dialog for '{}'", action, target);
}
else
{
Logger::error(L"ActionRunner: ShellExecuteEx failed for {} '{}': error {}", action, target, error);
}
return static_cast<int>(error);
}
Logger::trace(L"ActionRunner: Successfully launched '{}' with {}", target, action);
}
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">
<PlatformToolset>v143</PlatformToolset>
</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

@@ -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">
<PlatformToolset>v143</PlatformToolset>
</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);
}

82
src/Update/Resources.resx Normal file
View File

@@ -0,0 +1,82 @@
<?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" xml:space="preserve">
<value>An update to PowerToys is available.</value>
</data>
<data name="GITHUB_NEW_VERSION_UPDATE_NOW" xml:space="preserve">
<value>Update now</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>
<data name="GITHUB_NEW_VERSION_MORE_INFO" xml:space="preserve">
<value>More info...</value>
</data>
<data name="TOAST_TITLE" xml:space="preserve">
<value>PowerToys Update</value>
</data>
</root>

View File

@@ -1,22 +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.Update</AssemblyName>
<OutputPath>..\..\$(Platform)\$(Configuration)</OutputPath>
<Nullable>enable</Nullable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<PublishAot>true</PublishAot>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
<PropertyGroup>
<_IsPublishing Condition="'$(_IsPublishing)'==''">false</_IsPublishing>
</PropertyGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(_IsPublishing)'!='true'">
<Exec Command="dotnet publish &quot;$(ProjectPath)&quot; -c $(Configuration) -r $(RuntimeIdentifier) --self-contained -o &quot;$(OutputPath)&quot;" />
</Target>
</Project>

View File

@@ -1,227 +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.IO;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace Update
{
[SupportedOSPlatform("windows")]
public static class UpdateSettingsHelper
{
private static Thread? _updateThread;
private const string INSTALLERFILENAME = "powertoyssetup";
private const string USERINSTALLERFILENAME = "powertoysusersetup";
public static void TriggerUpdateCheck()
{
if (_updateThread is not null && _updateThread.IsAlive)
{
return;
}
_updateThread = new Thread(async () =>
{
UpdateInfo updateInfo = await GetUpdateAvailableInfo();
switch (updateInfo)
{
case UpdateInfo.UpdateCheckFailed ucf:
ProcessUpdateCheckFailed(ucf);
break;
case UpdateInfo.UpdateAvailable ua:
ProcessUpdateAvailable(ua);
break;
case UpdateInfo.NoUpdateAvailable:
ProcessNoUpdateAvailable();
break;
}
});
_updateThread.Start();
}
internal record UpdateInfo
{
private UpdateInfo()
{
}
public sealed record NoUpdateAvailable : UpdateInfo;
public sealed record UpdateAvailable(Uri ReleasePageUri, Version AvailableVersion, Uri InstallerDownloadUrl, string InstallerFilename) : UpdateInfo;
public sealed record UpdateCheckFailed(Exception Exception) : UpdateInfo;
}
internal static async Task<UpdateInfo> GetUpdateAvailableInfo()
{
Version? currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
if (currentVersion is null)
{
// Todo: Log
return new UpdateInfo.NoUpdateAvailable();
}
if (currentVersion is { Major: 0, Minor: 0 })
{
// Pre-release or local build, skip update check
return new UpdateInfo.NoUpdateAvailable();
}
try
{
HttpClient httpClient = new();
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("PowerToys Runner"); // GitHub API requires a user-agent
Stream body = await httpClient.GetStreamAsync("https://api.github.com/repos/microsoft/PowerToys/releases/latest").ConfigureAwait(false);
JsonElement releaseObject = (await JsonDocument.ParseAsync(body)).RootElement;
Version latestVersion = new(releaseObject.GetProperty("tag_name").GetString()?.TrimStart('V', 'v') ?? throw new FormatException("The \"tag_name\" field could not be found"));
string architectureString = RuntimeInformation.OSArchitecture switch
{
Architecture.X64 => "x64",
Architecture.Arm64 => "arm64",
_ => throw new InvalidDataException("Unknown architecture"),
};
if (latestVersion > currentVersion)
{
Uri releasePageUri = new(releaseObject.GetProperty("html_url").GetString() ?? throw new FormatException("The \"html_url\" field could not be found"));
string requiredFilename = GetInstallScope() == InstallScope.PerMachine ? INSTALLERFILENAME : USERINSTALLERFILENAME;
Uri? installerDownloadUrl = null;
string? installerFilename = null;
foreach (JsonElement asset in releaseObject.GetProperty("assets").EnumerateArray())
{
string? name = asset.GetProperty("name").GetString();
string? browserDownloadUrl = asset.GetProperty("browser_download_url").GetString();
if (name is null
|| browserDownloadUrl is null
|| !name.Contains(requiredFilename, StringComparison.InvariantCultureIgnoreCase)
|| !name.Contains(".exe", StringComparison.InvariantCultureIgnoreCase)
|| !name.Contains(architectureString, StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
installerDownloadUrl = new Uri(browserDownloadUrl);
installerFilename = name;
break;
}
return installerDownloadUrl is null || installerFilename is null
? new UpdateInfo.UpdateCheckFailed(new InvalidDataException("No installer found in GitHub release"))
: new UpdateInfo.UpdateAvailable(releasePageUri, latestVersion, installerDownloadUrl, installerFilename);
}
return new UpdateInfo.NoUpdateAvailable();
}
catch (Exception e)
{
return new UpdateInfo.UpdateCheckFailed(e);
}
}
private enum InstallScope
{
PerMachine,
PerUser,
}
[SupportedOSPlatform("windows")]
private static InstallScope GetInstallScope()
{
if (Registry.LocalMachine.OpenSubKey(@"Software\Classes\powertoys\", false) is not RegistryKey machineKey)
{
if (Registry.CurrentUser.OpenSubKey(@"Software\Classes\powertoys\", false) is not RegistryKey userKey)
{
// Both keys are missing
return InstallScope.PerMachine;
}
if (userKey.GetValue("InstallScope") is not string installScope)
{
userKey.Close();
return InstallScope.PerMachine;
}
userKey.Close();
return installScope.Contains("perUser") ? InstallScope.PerUser : InstallScope.PerMachine;
}
machineKey.Close();
return InstallScope.PerMachine;
}
private static readonly string _settingsPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft",
"PowerToys");
private static readonly string _updatingSettingsFile = Path.Combine(_settingsPath, "UpdateState.json");
private static void ProcessUpdateAvailable(UpdateInfo.UpdateAvailable updateAvailable)
{
UpdatingSettings updatingSettings = UpdatingSettings.LoadSettings();
Console.WriteLine($"Update available: {updateAvailable.AvailableVersion}");
updatingSettings.State = UpdatingSettings.UpdatingState.ReadyToDownload;
updatingSettings.ReleasePageLink = updateAvailable.ReleasePageUri.ToString();
updatingSettings.DownloadedInstallerFilename = updateAvailable.InstallerFilename;
updatingSettings.ReleasePageLink = updateAvailable.ReleasePageUri.ToString();
updatingSettings.LastCheckedDate = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture);
File.WriteAllText(_updatingSettingsFile, updatingSettings.ToJsonString());
}
internal static void ProcessNoUpdateAvailable()
{
UpdatingSettings updatingSettings = UpdatingSettings.LoadSettings();
updatingSettings.State = UpdatingSettings.UpdatingState.UpToDate;
updatingSettings.ReleasePageLink = string.Empty;
updatingSettings.DownloadedInstallerFilename = string.Empty;
updatingSettings.ReleasePageLink = string.Empty;
updatingSettings.LastCheckedDate = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture);
File.WriteAllText(_updatingSettingsFile, updatingSettings.ToJsonString());
}
private static void ProcessUpdateCheckFailed(UpdateInfo.UpdateCheckFailed updateCheckFailed)
{
// Todo: Log failed attempt
UpdatingSettings updatingSettings = UpdatingSettings.LoadSettings();
updatingSettings.State = UpdatingSettings.UpdatingState.NetworkError;
updatingSettings.ReleasePageLink = string.Empty;
updatingSettings.DownloadedInstallerFilename = string.Empty;
updatingSettings.ReleasePageLink = string.Empty;
updatingSettings.LastCheckedDate = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture);
File.WriteAllText(_updatingSettingsFile, updatingSettings.ToJsonString());
}
internal static void SetUpdateState(UpdatingSettings.UpdatingState state)
{
UpdatingSettings updatingSettings = UpdatingSettings.LoadSettings();
updatingSettings.State = state;
File.WriteAllText(_updatingSettingsFile, updatingSettings.ToJsonString());
}
internal static UpdatingSettings.UpdatingState GetUpdateState() => UpdatingSettings.LoadSettings().State;
}
}

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.
using System;
using System.Collections.Generic;
using System.Text;
namespace Update
{
internal static class UpdateStage
{
internal const string UPDATENOWLAUNCHSTAGE1 = "-update_now";
internal const string UPDATENOWLAUNCHSTAGE2 = "-update_now_stage_2";
}
}

View File

@@ -1,44 +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.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Update
{
public static class UpdateUtilities
{
public static async void UninstallPreviousMsixVersions()
{
try
{
Windows.Management.Deployment.PackageManager packageManager = new();
var packages = packageManager.FindPackagesForUser(string.Empty, "Microsoft.PowerToys", "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US");
Version? currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
if (currentVersion == null)
{
return;
}
foreach (var package in packages)
{
Version msixVersion = new Version(package.Id.Version.Major, package.Id.Version.Minor, package.Id.Version.Revision);
if (msixVersion < currentVersion)
{
await packageManager.RemovePackageAsync(package.Id.FullName);
}
}
}
catch
{
}
}
}
}

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.Globalization;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Update
{
public sealed class UpdatingSettings
{
public enum UpdatingState
{
UpToDate = 0,
ErrorDownloading,
ReadyToDownload,
ReadyToInstall,
NetworkError,
}
// Gets or sets a value of the updating state
[JsonPropertyName("state")]
public UpdatingState State { get; set; }
// Gets or sets a value of the release page url
[JsonPropertyName("releasePageUrl")]
public string ReleasePageLink { get; set; } = string.Empty;
// Gets or sets a value of the github last checked date
[JsonPropertyName("githubUpdateLastCheckedDate")]
public string LastCheckedDate { get; set; } = string.Empty;
// Gets or sets a value of the updating state
[JsonPropertyName("downloadedInstallerFilename")]
public string DownloadedInstallerFilename { get; set; } = string.Empty;
// Non-localizable strings: Files
public const string SettingsFilePath = "\\Microsoft\\PowerToys\\";
public const string SettingsFile = "UpdateState.json";
public string NewVersion
{
get
{
if (ReleasePageLink == null)
{
return string.Empty;
}
try
{
string version = ReleasePageLink.Substring(ReleasePageLink.LastIndexOf('/') + 1);
return version.Trim();
}
catch (Exception)
{
}
return string.Empty;
}
}
public string LastCheckedDateLocalized
{
get
{
try
{
if (LastCheckedDate == null)
{
return string.Empty;
}
long seconds = long.Parse(LastCheckedDate, CultureInfo.CurrentCulture);
var date = DateTimeOffset.FromUnixTimeSeconds(seconds).UtcDateTime;
return date.ToLocalTime().ToString(CultureInfo.CurrentCulture);
}
catch (Exception)
{
}
return string.Empty;
}
}
public UpdatingSettings()
{
State = UpdatingState.UpToDate;
}
public static UpdatingSettings LoadSettings()
{
var localAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var file = localAppDataDir + SettingsFilePath + SettingsFile;
if (File.Exists(file))
{
try
{
FileStream inputStream = File.Open(file, FileMode.Open);
StreamReader reader = new(inputStream);
string data = reader.ReadToEnd();
inputStream.Close();
reader.Dispose();
return JsonSerializer.Deserialize(data, UpdatingsSettingsSourceGenerationContext.Default.UpdatingSettings)!;
}
catch (Exception)
{
}
}
return new UpdatingSettings();
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this, UpdatingsSettingsSourceGenerationContext.Default.UpdatingSettings);
}
}
}

View File

@@ -1,22 +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.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Tasks;
namespace Update
{
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(UpdatingSettings))]
internal sealed partial class UpdatingsSettingsSourceGenerationContext : JsonSerializerContext
{
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
</packages>

View File

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

View File

@@ -0,0 +1,85 @@
#include "comUtils.h"
#include <Windows.h>
#pragma warning(push)
#pragma warning(disable : 4067)
#include <Sddl.h>
#pragma warning(pop)
#include <memory>
#include <wil/resource.h>
// Helper class for various COM-related APIs, e.g working with security descriptors
template<typename T>
struct typed_storage
{
std::unique_ptr<char[]> _buffer;
inline explicit typed_storage(const DWORD size) :
_buffer{ std::make_unique<char[]>(size) }
{
}
inline operator T*()
{
return reinterpret_cast<T*>(_buffer.get());
}
};
bool initializeCOMSecurity(const wchar_t* securityDescriptor)
{
PSECURITY_DESCRIPTOR self_relative_sd{};
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(securityDescriptor, SDDL_REVISION_1, &self_relative_sd, nullptr))
{
return false;
}
auto free_relative_sd = wil::scope_exit([&] {
LocalFree(self_relative_sd);
});
DWORD absolute_sd_size = 0;
DWORD dacl_size = 0;
DWORD group_size = 0;
DWORD owner_size = 0;
DWORD sacl_size = 0;
if (!MakeAbsoluteSD(self_relative_sd, nullptr, &absolute_sd_size, nullptr, &dacl_size, nullptr, &sacl_size, nullptr, &owner_size, nullptr, &group_size))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
return false;
}
}
typed_storage<SECURITY_DESCRIPTOR> absolute_sd{ absolute_sd_size };
typed_storage<ACL> dacl{ dacl_size };
typed_storage<ACL> sacl{ sacl_size };
typed_storage<SID> owner{ owner_size };
typed_storage<SID> group{ group_size };
if (!MakeAbsoluteSD(self_relative_sd,
absolute_sd,
&absolute_sd_size,
dacl,
&dacl_size,
sacl,
&sacl_size,
owner,
&owner_size,
group,
&group_size))
{
return false;
}
return !FAILED(CoInitializeSecurity(
absolute_sd,
-1,
nullptr,
nullptr,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IDENTIFY,
nullptr,
EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA,
nullptr));
}

View File

@@ -0,0 +1,3 @@
#pragma once
bool initializeCOMSecurity(const wchar_t* securityDescriptor);

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{7319089E-46D6-4400-BC65-E39BDF1416EE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>COMUtils</RootNamespace>
<ProjectName>COMUtils</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalIncludeDirectories>..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="comUtils.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="comUtils.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<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.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,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
</packages>

View File

@@ -98,6 +98,11 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\version\version.vcxproj">
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ExprtkEvaluator.h" />
<ClInclude Include="pch.h" />

View File

@@ -12,13 +12,9 @@
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="ExprtkEvaluator.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="ExprtkEvaluator.h" />
<ClInclude Include="exprtk.hpp" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<Midl Include="Calculator.idl" />
@@ -30,9 +26,4 @@
<ItemGroup>
<None Include="PropertySheet.props" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="CalculatorEngineCommon.rc">
<Filter>Resources</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -1,6 +1,6 @@
#include <windows.h>
#include "resource.h"
#include "../../../common/utils/version.h"
#include "../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"

View File

@@ -109,6 +109,11 @@
<ItemGroup>
<ResourceCompile Include="GPOWrapper.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\version\version.vcxproj">
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<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')" />

View File

@@ -71,10 +71,5 @@ namespace PowerToys.GPOWrapperProjection
{
return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredLightSwitchEnabledValue();
}
public static GpoRuleConfigured GetDisableShowWhatsNewAfterUpdatesValue()
{
return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetDisableShowWhatsNewAfterUpdatesValue();
}
}
}

View File

@@ -1,8 +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 ManagedCommon
{
public record HotkeyEx(ushort ModifiersMask, ushort VkCode, int Identifier);
}

View File

@@ -18,7 +18,7 @@ namespace ManagedCommon
internal sealed class OutGoingLanguageSettings
{
[JsonPropertyName("language")]
public string? LanguageTag { get; set; }
public string LanguageTag { get; set; }
}
public static string LoadLanguage()
@@ -36,7 +36,7 @@ namespace ManagedCommon
inputStream.Close();
reader.Dispose();
return JsonSerializer.Deserialize<OutGoingLanguageSettings>(data, SourceGenerationContext.Default.OutGoingLanguageSettings)!.LanguageTag!;
return JsonSerializer.Deserialize<OutGoingLanguageSettings>(data, SourceGenerationContext.Default.OutGoingLanguageSettings).LanguageTag;
}
catch (Exception)
{

View File

@@ -29,17 +29,17 @@ namespace ManagedCommon
/// <summary>
/// Gets the path to the log directory for the current version of the app.
/// </summary>
public static string? CurrentVersionLogDirectoryPath { get; private set; }
public static string CurrentVersionLogDirectoryPath { get; private set; }
/// <summary>
/// Gets the path to the current log file.
/// </summary>
public static string? CurrentLogFile { get; private set; }
public static string CurrentLogFile { get; private set; }
/// <summary>
/// Gets the path to the log directory for the app.
/// </summary>
public static string? AppLogDirectoryPath { get; private set; }
public static string AppLogDirectoryPath { get; private set; }
/// <summary>
/// Initializes the logger and sets the path for logging.
@@ -50,7 +50,7 @@ namespace ManagedCommon
public static void InitializeLogger(string applicationLogPath, bool isLocalLow = false)
{
string versionedPath = LogDirectoryPath(applicationLogPath, isLocalLow);
string basePath = Path.GetDirectoryName(versionedPath)!;
string basePath = Path.GetDirectoryName(versionedPath);
if (!Directory.Exists(versionedPath))
{

View File

@@ -6,7 +6,6 @@
<PropertyGroup>
<Description>PowerToys ManagedCommon</Description>
<AssemblyName>PowerToys.ManagedCommon</AssemblyName>
<Nullable>enable</Nullable>
</PropertyGroup>
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->
@@ -21,7 +20,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GPOWrapperProjection\GPOWrapperProjection.csproj" />
<ProjectReference Include="..\interop\PowerToys.Interop.vcxproj" />
<ProjectReference Include="..\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
</ItemGroup>

View File

@@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
namespace ManagedCommon
{
internal static partial class NativeMethods
internal static class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);
@@ -21,13 +21,6 @@ namespace ManagedCommon
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, System.Text.StringBuilder lpExeName, ref uint lpdwSize);
[LibraryImport("kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
internal static partial IntPtr CreateEventW(IntPtr lpEventAttributes, [MarshalAs(UnmanagedType.Bool)] bool bManualReset, [MarshalAs(UnmanagedType.Bool)] bool bInitialState, string lpName);
[LibraryImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool SetEvent(IntPtr hEvent);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);

View File

@@ -20,7 +20,7 @@ namespace ManagedCommon
/// Gets the PowerToys installation path by checking registry entries
/// </summary>
/// <returns>The path to PowerToys installation directory, or null if not found</returns>
public static string? GetPowerToysInstallPath()
public static string GetPowerToysInstallPath()
{
#if DEBUG
// In debug builds, resolve directly from the running process (no installer/registry involved).
@@ -44,14 +44,14 @@ namespace ManagedCommon
#endif
}
private static string? GetPathFromRegistry(RegistryHive hive)
private static string GetPathFromRegistry(RegistryHive hive)
{
try
{
using var baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Registry64);
// First try to get path from the powertoys protocol registration
string? path = GetPathFromProtocolRegistration(baseKey);
string path = GetPathFromProtocolRegistration(baseKey);
if (!string.IsNullOrEmpty(path))
{
return path;
@@ -65,7 +65,7 @@ namespace ManagedCommon
return null;
}
private static string? GetPathFromProtocolRegistration(RegistryKey baseKey)
private static string GetPathFromProtocolRegistration(RegistryKey baseKey)
{
try
{
@@ -73,7 +73,7 @@ namespace ManagedCommon
if (key != null)
{
string? command = key.GetValue(string.Empty)?.ToString();
string command = key.GetValue(string.Empty)?.ToString();
if (!string.IsNullOrEmpty(command))
{
// Parse command like: "C:\Program Files\PowerToys\PowerToys.exe" "%1"
@@ -89,7 +89,7 @@ namespace ManagedCommon
return null;
}
private static string? GetPathFromCurrentProcess()
private static string GetPathFromCurrentProcess()
{
try
{
@@ -125,7 +125,7 @@ namespace ManagedCommon
return null;
}
private static string? ExtractPathFromCommand(string command)
private static string ExtractPathFromCommand(string command)
{
if (string.IsNullOrEmpty(command))
{

View File

@@ -24,7 +24,7 @@ namespace ManagedCommon
// based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application
public static AppTheme GetAppTheme()
{
int value = (int)Registry.GetValue($"{HKeyRoot}\\{HkeyWindowsPersonalizeTheme}", HValueAppTheme, 1)!;
int value = (int)Registry.GetValue($"{HKeyRoot}\\{HkeyWindowsPersonalizeTheme}", HValueAppTheme, 1);
return (AppTheme)value;
}

View File

@@ -24,7 +24,7 @@ namespace ManagedCommon
/// <summary>
/// An event that fires if the Theme changes.
/// </summary>
public event ThemeChangedEvent? ThemeChanged;
public event ThemeChangedEvent ThemeChanged;
private readonly ManagementEventWatcher watcher;
@@ -33,7 +33,7 @@ namespace ManagedCommon
var currentUser = WindowsIdentity.GetCurrent();
var query = new WqlEventQuery(
$"SELECT * FROM RegistryValueChangeEvent WHERE Hive='HKEY_USERS' AND " +
$"KeyPath='{currentUser.User?.Value}\\\\{ThemeHelpers.HkeyWindowsPersonalizeTheme.Replace("\\", "\\\\")}' AND ValueName='{ThemeHelpers.HValueAppTheme}'");
$"KeyPath='{currentUser.User.Value}\\\\{ThemeHelpers.HkeyWindowsPersonalizeTheme.Replace("\\", "\\\\")}' AND ValueName='{ThemeHelpers.HValueAppTheme}'");
watcher = new ManagementEventWatcher(query);
watcher.EventArrived += Watcher_EventArrived;
watcher.Start();

View File

@@ -1,6 +1,7 @@
<?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')" />
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{6955446D-23F7-4023-9BB3-8657F904AF99}</ProjectGuid>
@@ -43,6 +44,9 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\common\version\version.vcxproj">
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
</ProjectReference>
<ProjectReference Include="..\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>

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