FancyZones and Shortcut Guide initial commit

Co-authored-by: Alexis Campailla <alexis@janeasystems.com>
Co-authored-by: Bret Anderson <bretan@microsoft.com>
Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Jeff Bogdan <jeffbog@microsoft.com>
Co-authored-by: March Rogers <marchr@microsoft.com>
Co-authored-by: Mike Harsh <mharsh@microsoft.com>
Co-authored-by: Nachum Bundak <Nachum.Bundak@microsoft.com>
Co-authored-by: Oliver Jones <ojones@microsoft.com>
Co-authored-by: Patrick Little <plittle@microsoft.com>
This commit is contained in:
Bartosz Sosnowski 2019-09-04 18:26:26 +02:00 committed by Bartosz Sosnowski
parent 10c5396099
commit 8431b80e48
341 changed files with 55009 additions and 62 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
*.rc diff

37
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,37 @@
---
name: Bug report
about: Report errors or unexpected behavior
title: ''
labels: ''
assignees: ''
---
<!--
**Important: When reporting BSODs or security issues, DO NOT attach memory dumps, logs, or traces to Github issues**.
Instead, send dumps/traces to secure@microsoft.com, referencing this GitHub issue.
-->
# Environment
```
Windows build number: [run "ver" at a command prompt]
PowerToys version:
PowerToy module for which you are reporting the bug (if applicable):
```
# Steps to reproduce
<!-- A description of how to trigger this bug. -->
# Expected behavior
<!-- A description of what you're expecting, possibly containing screenshots or reference material. -->
# Actual behavior
<!-- What's actually happening? -->
# Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->

View file

@ -0,0 +1,10 @@
---
name: Documentation Issue
about: Report issues in our documentation
title: ''
labels: ''
assignees: ''
---
<!-- Briefly describe which document needs to be corrected and why. -->

View file

@ -0,0 +1,21 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
# Summary of the new feature/enhancement
<!--
A clear and concise description of what the problem is that the new feature would solve.
Describe why and how a user would use this new functionality (if applicable).
-->
# Proposed technical implementation details (optional)
<!--
A clear and concise description of what you want to happen.
-->

19
.github/pull_request_template.md vendored Normal file
View file

@ -0,0 +1,19 @@
<!-- 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
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #xxx
* [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA
* [ ] Tests added/passed
* [ ] Requires documentation to be updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #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

2
.pipelines/build.cmd Normal file
View file

@ -0,0 +1,2 @@
cd /D "%~dp0"
dotnet build --no-restore ..\PowerToys.sln || exit /b 1

View file

@ -0,0 +1,43 @@
environment:
host:
os: 'windows'
flavor: 'server'
version: '2016'
runtime:
provider: 'appcontainer'
image: 'cdpxwinrs4test.azurecr.io/global/vse2017u7-external-azsdk-mobile-ext-win1803:latest-nodetools'
source_mode: 'link'
signing_options:
profile: 'azure'
package_sources:
nuget:
feeds:
'Toolset': 'https://msazure.pkgs.visualstudio.com/_packaging/Toolset/nuget/v3/index.json'
'CloudES-CDP': 'https://cloudes.pkgs.visualstudio.com/_packaging/CDP/nuget/v3/index.json'
'CloudES-Internal': 'https://cloudes.pkgs.visualstudio.com/_packaging/Internal/nuget/v3/index.json'
'MsNugetMirror': 'https://msazure.pkgs.visualstudio.com/_packaging/MsNugetMirror/nuget/v3/index.json'
'NugetMirror': 'https://msazure.pkgs.visualstudio.com/_packaging/NugetMirror/nuget/v3/index.json'
'CorextMirror': 'https://msazure.pkgs.visualstudio.com/_packaging/CorextMirror/nuget/v3/index.json'
'Official': 'https://msazure.pkgs.visualstudio.com/_packaging/Official/nuget/v3/index.json'
'Toolset': 'https://msazure.pkgs.visualstudio.com/_packaging/Toolset/nuget/v3/index.json'
'AzureCXP': 'https://msazure.pkgs.visualstudio.com/_packaging/AzureCXP/nuget/v3/index.json'
restore:
commands:
- !!defaultcommand
name: 'Restore CSharp'
command: '.pipelines\restore.cmd'
build:
commands:
- !!buildcommand
name: 'Build CSharp'
command: '.pipelines\build.cmd'
artifacts:
- from: '**\bin'
to: 'Build_Output'
include:
- '**/*'

3
.pipelines/restore.cmd Normal file
View file

@ -0,0 +1,3 @@
cd /D "%~dp0"
dotnet restore ..\PowerToys.sln || exit /b 1

BIN
License.rtf Normal file

Binary file not shown.

120
PowerToys.sln Normal file
View file

@ -0,0 +1,120 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.452
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner.vcxproj", "{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}"
ProjectSection(ProjectDependencies) = postProject
{48804216-2A0E-4168-A6D8-9CD068D14227} = {48804216-2A0E-4168-A6D8-9CD068D14227}
{74485049-C722-400F-ABE5-86AC52D929B3} = {74485049-C722-400F-ABE5-86AC52D929B3}
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA} = {A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}
{07C389E3-6BC8-41CF-923E-307B1265FA2D} = {07C389E3-6BC8-41CF-923E-307B1265FA2D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "src\common\common.vcxproj", "{74485049-C722-400F-ABE5-86AC52D929B3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shortcut_guide", "src\modules\shortcut_guide\shortcut_guide.vcxproj", "{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_powertoy", "src\modules\example_powertoy\example_powertoy.vcxproj", "{44CC9375-3E6E-4D99-8913-7FB748807EBD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{4574FDD0-F61D-4376-98BF-E5A1262C11EC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "interface", "interface", "{3BB8493E-D18E-4485-A320-CB40F90F55AE}"
ProjectSection(SolutionItems) = preProject
src\modules\interface\lowlevel_keyboard_event_data.h = src\modules\interface\lowlevel_keyboard_event_data.h
src\modules\interface\powertoy_module_interface.h = src\modules\interface\powertoy_module_interface.h
src\modules\interface\win_hook_event_data.h = src\modules\interface\win_hook_event_data.h
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "src\editor\settings.vcxproj", "{07C389E3-6BC8-41CF-923E-307B1265FA2D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fancyzones", "fancyzones", "{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesLib", "src\modules\fancyzones\lib\FancyZonesLib.vcxproj", "{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fancyzones", "src\modules\fancyzones\dll\FancyZonesModule.vcxproj", "{48804216-2A0E-4168-A6D8-9CD068D14227}"
ProjectSection(ProjectDependencies) = postProject
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests-FancyZones", "src\modules\fancyzones\tests\UnitTests\UnitTests.vcxproj", "{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk", "deps\cpprestsdk\cpprestsdk.vcxproj", "{4E577735-DFAB-41AF-8A6E-B6E8872A2928}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deps", "deps", "{1FAF749F-0D6F-4BF5-A563-31A4B5279D27}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{1AFB6476-670D-4E80-A464-657E01DFF482}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests-CommonLib", "src\common\UnitTests-CommonLib\UnitTests-CommonLib.vcxproj", "{1A066C63-64B3-45F8-92FE-664E1CCE8077}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZonesEditor", "src\modules\fancyzones\editor\FancyZonesEditor\FancyZonesEditor.csproj", "{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.ActiveCfg = Debug|x64
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.Build.0 = Debug|x64
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.ActiveCfg = Release|x64
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.Build.0 = Release|x64
{74485049-C722-400F-ABE5-86AC52D929B3}.Debug|x64.ActiveCfg = Debug|x64
{74485049-C722-400F-ABE5-86AC52D929B3}.Debug|x64.Build.0 = Debug|x64
{74485049-C722-400F-ABE5-86AC52D929B3}.Release|x64.ActiveCfg = Release|x64
{74485049-C722-400F-ABE5-86AC52D929B3}.Release|x64.Build.0 = Release|x64
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Debug|x64.ActiveCfg = Debug|x64
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Debug|x64.Build.0 = Debug|x64
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x64.ActiveCfg = Release|x64
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA}.Release|x64.Build.0 = Release|x64
{44CC9375-3E6E-4D99-8913-7FB748807EBD}.Debug|x64.ActiveCfg = Debug|x64
{44CC9375-3E6E-4D99-8913-7FB748807EBD}.Release|x64.ActiveCfg = Release|x64
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Debug|x64.ActiveCfg = Debug|x64
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Debug|x64.Build.0 = Debug|x64
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Release|x64.ActiveCfg = Release|x64
{07C389E3-6BC8-41CF-923E-307B1265FA2D}.Release|x64.Build.0 = Release|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.ActiveCfg = Debug|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.Build.0 = Debug|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.ActiveCfg = Release|x64
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.Build.0 = Release|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.ActiveCfg = Debug|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.Build.0 = Debug|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.ActiveCfg = Release|x64
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.Build.0 = Release|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.ActiveCfg = Debug|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.Build.0 = Debug|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.ActiveCfg = Release|x64
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.Build.0 = Release|x64
{4E577735-DFAB-41AF-8A6E-B6E8872A2928}.Debug|x64.ActiveCfg = Debug|x64
{4E577735-DFAB-41AF-8A6E-B6E8872A2928}.Debug|x64.Build.0 = Debug|x64
{4E577735-DFAB-41AF-8A6E-B6E8872A2928}.Release|x64.ActiveCfg = Release|x64
{4E577735-DFAB-41AF-8A6E-B6E8872A2928}.Release|x64.Build.0 = Release|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.ActiveCfg = Debug|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.Build.0 = Debug|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.ActiveCfg = Release|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.Build.0 = Release|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.ActiveCfg = Debug|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.Build.0 = Debug|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.ActiveCfg = Release|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{74485049-C722-400F-ABE5-86AC52D929B3} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{A46629C4-1A6C-40FA-A8B6-10E5102BB0BA} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{44CC9375-3E6E-4D99-8913-7FB748807EBD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{3BB8493E-D18E-4485-A320-CB40F90F55AE} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{48804216-2A0E-4168-A6D8-9CD068D14227} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{4E577735-DFAB-41AF-8A6E-B6E8872A2928} = {1FAF749F-0D6F-4BF5-A563-31A4B5279D27}
{1A066C63-64B3-45F8-92FE-664E1CCE8077} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
EndGlobalSection
EndGlobal

169
README.md
View file

@ -1,62 +1,107 @@
# Overview
PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity.
Inspired by the [Windows 95 era PowerToys project](https://en.wikipedia.org/wiki/Microsoft_PowerToys), this reboot provides power users with ways to squeeze more efficiency out of the Windows 10 shell and customize it for individual workflows. A great overview of the Windows 95 PowerToys can be found [here](https://socket3.wordpress.com/2016/10/22/using-windows-95-powertoys/).
The first preview of these utilities and corresponding source code will be released Summer 2019.
![logo](Logo.jpg)
# What's Happening
## June Update
Since the announcement of the PowerToys reboot at BUILD, the interest in the project has been incredible to see. Due to the excitement we are optimizing the first preview to make it easy to integrate new utilities into the repo. We also have two interns working on additional PowerToys. The specs for these are:
* [Process terminate tool](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/Terminate%20Spec.md)
* [Batch file renamer](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/File%20Classification%20Spec.md)
* [Animated gif screen recorder](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/GIF%20Maker%20Spec.md)
Finally, we are organizing a team to productize an internal window manager into the PowerToys project for the 2019 [One Week Hackathon](https://www.onmsft.com/news/take-a-peek-inside-microsofts-recent-one-week-hackathon).
We are still targeting to release the preview and code during Summer 2019.
## The first two utilities we're working on are:
1. Maximize to new desktop widget - The MTND widget shows a pop-up button when a user hovers over the maximize / restore button on any window. Clicking it creates a new desktop, sends the app to that desktop and maximizes the app on the new desktop.
![Maximize to new desktop widget](MTNDWidget.jpg)
2. Windows key shortcut guide - The shortcut guide appears when a user holds the Windows key down for more than one second and shows the available shortcuts for the current state of the desktop.
![Windows key shortcut guide](WindowsKeyShortcutGuide.jpg)
# Backlog
Here's the current set of utilities we're considering. Please use issues and +1's to guide the project to suggest new ideas and help us prioritize the list below.
1. [Full window manager including specific layouts for docking and undocking laptops](https://github.com/microsoft/PowerToys/issues/4)
2. [Keyboard shortcut manager](https://github.com/microsoft/PowerToys/issues/6)
3. [Win+R replacement](https://github.com/microsoft/PowerToys/issues/44)
4. Better Alt+Tab including browser tab integration and search for running apps
5. [Battery tracker](https://github.com/microsoft/PowerToys/issues/7)
6. [Batch file re-namer](https://github.com/microsoft/PowerToys/issues/101)
7. [Quick resolution swaps in taskbar](https://github.com/microsoft/PowerToys/issues/27)
8. Mouse events without focus
9. Cmd (or PS or Bash) from here
10. Contents menu file browsing
# Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
# Overview
PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity.
Inspired by the [Windows 95 era PowerToys project](https://en.wikipedia.org/wiki/Microsoft_PowerToys), this reboot provides power users with ways to squeeze more efficiency out of the Windows 10 shell and customize it for individual workflows. A great overview of the Windows 95 PowerToys can be found [here](https://socket3.wordpress.com/2016/10/22/using-windows-95-powertoys/).
The first preview of these utilities can be installed from [here](https://github.com/Microsoft/powertoys/releases).
![logo](doc/images/Logo.jpg)
# What's Happening
## September Update
The first preview release of the PowerToys utilities and source code is now live! This release includes two preview quality utilities as well as the tools and docs to make it easy to create new PowerToys utilities.
1. [FancyZones](/src/modules/fancyzones/) - FancyZones is a window manager that makes it easy to create copmlex window layouts and quickly position windows into those layouts. The FancyZones backlog can be found [here](https://github.com/Microsoft/PowerToys/tree/master/doc/planning/FancyZonesBacklog.md)
![FancyZones](src/modules/fancyzones/FancyZones.png)
FanzyZones Video Tutorial
[![FancyZones Video Tutorial](doc/images/FZTutorial.jpg)](https://www.youtube.com/watch?v=rTtGzZYAXgY)
2. [Windows key shortcut guide](/src/modules/shortcut_guide) - The shortcut guide appears when a user holds the Windows key down for more than one second and shows the available shortcuts for the current state of the desktop. The shortcut guide backlog can be found [here](https://github.com/Microsoft/PowerToys/tree/master/doc/planning/ShortcutGuideBacklog.md)
![Windows key shortcut guide](doc/images/WindowsKeyShortcutGuide.jpg)
Additional utilities in the pipeline are:
* Maximize to new desktop widget - The MTND widget shows a pop-up button when a user hovers over the maximize / restore button on any window. Clicking it creates a new desktop, sends the app to that desktop and maximizes the app on the new desktop.
* [Process terminate tool](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/Terminate%20Spec.md)
* [Batch file renamer](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/File%20Classification%20Spec.md)
* [Animated gif screen recorder](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/GIF%20Maker%20Spec.md)
# Backlog
The full backlog of utilities can be found [here](https://github.com/Microsoft/PowerToys/tree/master/doc/planning/PowerToysBacklog.md)
# Where to download PowerToys
The latest release of PowerToys can be downloaded from https://github.com/microsoft/PowerToys/releases <br />
Click on `Assets` to show the files available in the release and then click on `PowerToysSetup.msi` to download the PowerToys installer. <br />
PDB symbols for the release are available in a separate zip file `PDB symbols.zip`.
# Developer Guidance
## Build Prerequisites
* Windows 10 1803 (build 10.0.17134.0) or above in order to build and run PowerToys.
* Visual Studio 2019 Community edition or higher, with the 'Desktop Development with C++' component and the Windows 10 SDK version 10.0.18362.0 or higher.
## Building the Code
* Open `powertoys.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
* The PowerToys binaries will be located in your repo under `x64\Release`.
* If you want to copy the `PowerToys.exe` binary to a different location, you'll also need to copy the `modules` and the `svgs` folders.
## Prerequisites to Build the Installer
* Install the [WiX Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=RobMensching.WiXToolset).
* Install the [WiX Toolset build tools](https://wixtoolset.org/releases/).
## Building the .msi Installer
* From the `installer` folder open `PowerToysSetup.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
* The resulting `PowerToysSetup.msi` installer will be available in the `installer\PowerToysSetup\x64\Release\` folder.
## Debugging
The following configuration issue only applies if the user is a member of the Administrators group.
Some PowerToys modules require to run with the highest permission level if the current user is a member of the Administrators group. The highest permission level is required in order to be able to perform some actions when an elevated application (e.g. Task Manager) is in the foreground or is the target of an action. Without elevated privileges some PowerToys modules will still work but with some limitations:
- the `FancyZones` module will be not be able to move an elevated window to a zone.
- the `Shortcut Guide` module will not appear if the foreground window belongs to an elevated application.
In order to run and debug PowerToys from Visual Studio when the user is a member of the Administrators group, Visual Studio has to be started with elevated privileges. If you want to avoid running Visual Studio with elevated privileges and don't mind the limitations described above, you can do the following: open the `runner` project properties and navigate to the `Linker -> Manifest File` settings, edit the `UAC Execution Level` property and change it from `highestAvailable (/level='highestAvailable')` to `asInvoker (/level='asInvoker')`, save the changes.
## How to create new PowerToys
See the instructions on [how to install the PowerToys Module project template](tools/project_template). <br />
Specifications for the [PowerToys settings API](doc/specs/PowerToys-settings.md).
## Coding Guidance
Please review these brief docs below relating to our coding standards etc.
> 👉 If you find something missing from these docs, feel free to contribute to any of our documentation files anywhere in the repository (or make some new ones\!)
This is a work in progress as we learn what we'll need to provide people in order to be effective contributors to our project.
- [Coding Style](doc/coding/style.md)
- [Code Organization](doc/coding/organization.md)
# Contributing
This project welcomes contributions and suggestions and we are excited to work with the power user community to build a set of tools for helping you get the most our of Windows.
We ask that **before you start work on a feature that you would like to contribute**, please read our [Contributor's Guide](contributing.md). We will be happy to work with you to figure out the best approach, provide guidance and mentorship throughout feature development, and help avoid any wasted or duplicate effort.
> ⚠ **Note**: PowerToys is still a nascent project and the team is actively working out of this repository. We will be periodically re-structuring the code to make it easier to comprehend, navigate, build, test, and contribute to, so **DO expect significant changes to code layout on a regular basis**.
> ⚠ **License Info**: Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
# Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct][conduct-code]. <br />
For more information see the [Code of Conduct FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any additional questions or comments.
[conduct-code]: https://opensource.microsoft.com/codeofconduct/
[conduct-FAQ]: https://opensource.microsoft.com/codeofconduct/faq/
[conduct-email]: mailto:opencode@microsoft.com

24
build/pipelines/ci.yml Normal file
View file

@ -0,0 +1,24 @@
trigger:
batch: true
branches:
include:
- master
paths:
exclude:
- doc/*
- temp/*
- tools/*
pr:
branches:
include:
- master
# 0.0.yyMM.dd##
# 0.0.1904.0900
name: 0.0.$(Date:yyMM).$(Date:dd)$(Rev:rr)
jobs:
- template: ./templates/build-powertoys-ci.yml
parameters:
platform: x64

View file

@ -0,0 +1,17 @@
parameters:
configuration: 'Release'
platform: ''
additionalBuildArguments: ''
jobs:
- job: Build${{ parameters.platform }}${{ parameters.configuration }}
displayName: Build ${{ parameters.platform }} ${{ parameters.configuration }}
variables:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
pool: { vmImage: windows-2019 }
steps:
- template: build-powertoys-steps.yml
parameters:
additionalBuildArguments: ${{ parameters.additionalBuildArguments }}

View file

@ -0,0 +1,35 @@
parameters:
additionalBuildArguments: ''
steps:
- checkout: self
submodules: true
clean: true
- task: NuGetToolInstaller@0
displayName: Ensure NuGet 4.8.1
inputs:
versionSpec: 4.8.1
- task: VisualStudioTestPlatformInstaller@1
displayName: Ensure VSTest Platform
- task: NuGetCommand@2
displayName: Restore NuGet packages
inputs:
command: restore
feedsToUse: config
configPath: NuGet.config
restoreSolution: PowerToys.sln
restoreDirectory: '$(Build.SourcesDirectory)\packages'
- task: VSBuild@1
displayName: 'Build solution **\PowerToys.sln'
inputs:
solution: '**\PowerToys.sln'
vsVersion: 15.0
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
msbuildArgs: ${{ parameters.additionalBuildArguments }}
clean: true
maximumCpuCount: true

128
contributing.md Normal file
View file

@ -0,0 +1,128 @@
# Power Toys Contributor's Guide
Below is our guidance for how to report issues, propose new features, and submit contributions via Pull Requests (PRs).
## Before you start, file an issue
Please follow this simple rule to help us eliminate any unnecessary wasted effort & frustration, and ensure an efficient and effective use of everyone's time - yours, ours, and other community members':
> 👉 If you have a question, think you've discovered an issue, would like to propose a new feature, etc., then find/file an issue **BEFORE** starting work to fix/implement it.
### Search existing issues first
Before filing a new issue, search existing open and closed issues first: It is likely someone else has found the problem you're seeing, and someone may be working on or have already contributed a fix!
If no existing item describes your issue/feature, great - please file a new issue:
### File a new Issue
* Don't know whether you're reporting an issue or requesting a feature? File an issue
* Have a question that you don't see answered in docs, videos, etc.? File an issue
* Want to know if we're planning on building a particular feature? File an issue
* Got a great idea for a new utility or feature? File an issue/request/idea
* Don't understand how to do something? File an issue/Community Guidance Request
* Found an existing issue that describes yours? Great - upvote and add additional commentary / info / repro-steps / etc.
### Complete the template
**Please include as much information as possible in your issue**. The more information you provide, the more likely your issue/ask will be understood and implemented. Helpful information includes:
* What device you're running (inc. CPU type, memory, disk, etc.)
* What build of Windows your device is running
👉 Tip: Run the following in PowerShell Core
```powershell
C:\> $PSVersionTable.OS
Microsoft Windows 10.0.18909
```
... or in Windows PowerShell
```powershell
C:\> $PSVersionTable.BuildVersion
Major Minor Build Revision
----- ----- ----- --------
10 0 18912 1001
```
... or Cmd:
```cmd
C:\> ver
Microsoft Windows [Version 10.0.18900.1001]
```
* What tools and apps you're using (e.g. VS 2019, VSCode, etc.)
* Don't assume we're experts in setting up YOUR environment and don't assume we are experts in YOUR workflow. Teach us to help you!
* **We LOVE detailed repro steps!** What steps do we need to take to reproduce the issue? Assume we love to read repro steps. As much detail as you can stand is probably _barely_ enough detail for us!
* Prefer error message text where possible or screenshots of errors if text cannot be captured
* **If you intend to implement the fix/feature yourself then say so!** If you do not indicate otherwise we will assume that the issue is our to solve, or may label the issue as `Help-Wanted`.
### DO NOT post "+1" comments
> ⚠ DO NOT post "+1", "me too", or similar comments - they just add noise to an issue.
If you don't have any additional info/context to add but would like to indicate that you're affected by the issue, upvote the original issue by clicking its [+😊] button and hitting 👍 (+1) icon. This way we can actually measure how impactful an issue is.
---
## Contributing fixes / features
For those able & willing to help fix issues and/or implement features ...
### To Spec or not to Spec
Some issues/features may be quick and simple to describe and understand. For such scenarios, once a team member has agreed with your approach, skip ahead to the section headed "Fork, Branch, and Create your PR", below.
Small issues that do not require a spec will be labelled Issue-Bug or Issue-Task.
However, some issues/features will require careful thought & formal design before implementation. For these scenarios, we'll request that a spec is written and the associated issue will be labeled Issue-Feature.
Specs help collaborators discuss different approaches to solve a problem, describe how the feature will behave, how the feature will impact the user, what happens if something goes wrong, etc. Driving towards agreement in a spec, before any code is written, often results in simpler code, and less wasted effort in the long run.
Specs will be managed in a very similar manner as code contributions so please follow the "Fork, Branch and Create your PR" below.
### Writing / Contributing-to a Spec
To write/contribute to a spec: fork, branch and commit via PRs, as you would with any code changes.
Specs are written in markdown, stored under the `doc/specs` folder and named `[issue id] - [spec description].md`.
👉 **It is important to follow the spec templates and complete the requested information**. The available spec templates will help ensure that specs contain the minimum information & decisions necessary to permit development to begin. In particular, specs require you to confirm that you've already discussed the issue/idea with the team in an issue and that you provide the issue ID for reference.
Team members will be happy to help review specs and guide them to completion.
### Help Wanted
Once the team have approved an issue/spec, development can proceed. If no developers are immediately available, the spec can be parked ready for a developer to get started. Parked specs' issues will be labeled "Help Wanted". To find a list of development opportunities waiting for developer involvement, visit the Issues and filter on [the Help-Wanted label](https://github.com/microsoft/PowerToys/labels/Help-Wanted).
---
## Development
### Fork, Clone, Branch and Create your PR
Once you've discussed your proposed feature/fix/etc. with a team member, and you've agreed an approach or a spec has been written and approved, it's time to start development:
1. Fork the repo if you haven't already
1. Clone your fork locally
1. Create & push a feature branch
1. Create a [Draft Pull Request (PR)](https://github.blog/2019-02-14-introducing-draft-pull-requests/)
1. Work on your changes
### Code Review
When you'd like the team to take a look, (even if the work is not yet fully-complete), mark the PR as 'Ready For Review' so that the team can review your work and provide comments, suggestions, and request changes. It may take several cycles, but the end result will be solid, testable, conformant code that is safe for us to merge.
### Merge
Once your code has been reviewed and approved by the requisite number of team members, it will be merged into the master branch. Once merged, your PR will be automatically closed.
---
## Thank you
Thank you in advance for your contribution!

12
deps/cpprestsdk/README.md vendored Normal file
View file

@ -0,0 +1,12 @@
# C++ Rest SDK - JSON library
This JSON library is taken from the C++ REST SDK in https://github.com/microsoft/cpprestsdk
Based in the [v2.10.13 release](https://github.com/microsoft/cpprestsdk/tree/v2.10.13/Release), it consists of the needed files to build and use the JSON classes described in `include/cpprest/json.h`.
Changes made to the files in order to build in the PowerToys project:
- Removal of `#include` references to files that are not needed.
- `#include "pch.h"` instead of `#include "stdafx.h"` to use the PowerToys pre-compiled header.
- `#define _NO_ASYNCRTIMP` in [`include/cpprest/details/cpprest_compat.h`](./include/cpprest/details/cpprest_compat.h) since this class will be statically linked.
The contents of the C++ Rest SDK license are included in [license.txt](./license.txt).

121
deps/cpprestsdk/cpprestsdk.vcxproj vendored Normal file
View file

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{4E577735-DFAB-41AF-8A6E-B6E8872A2928}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>common</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>cpprestsdk</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="include\cpprest\asyncrt_utils.h" />
<ClInclude Include="include\cpprest\base_uri.h" />
<ClInclude Include="include\cpprest\details\basic_types.h" />
<ClInclude Include="include\cpprest\details\cpprest_compat.h" />
<ClInclude Include="include\cpprest\details\SafeInt3.hpp" />
<ClInclude Include="include\cpprest\details\web_utilities.h" />
<ClInclude Include="include\cpprest\json.h" />
<ClInclude Include="include\cpprest\uri.h" />
<ClInclude Include="include\cpprest\uri_builder.h" />
<ClInclude Include="include\cpprest\version.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\json\json.cpp" />
<ClCompile Include="src\json\json_parsing.cpp" />
<ClCompile Include="src\json\json_serialization.cpp" />
<ClCompile Include="src\utilities\asyncrt_utils.cpp" />
<ClCompile Include="src\utilities\base64.cpp" />
<ClCompile Include="src\utilities\web_utilities.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,697 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Various common utilities.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include "cpprest/details/basic_types.h"
//#include "pplx/pplxtasks.h"
#include <chrono>
#include <cstdint>
#include <limits.h>
#include <locale.h>
#include <random>
#include <string>
#include <system_error>
#include <vector>
#ifndef _WIN32
#include <sys/time.h>
#if !defined(ANDROID) && !defined(__ANDROID__) && defined(HAVE_XLOCALE_H) // CodePlex 269
/* Systems using glibc: xlocale.h has been removed from glibc 2.26
The above include of locale.h is sufficient
Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b6336db7492e47d2e8e72eb8af53b5506d */
#include <xlocale.h>
#endif
#endif
/// Various utilities for string conversions and date and time manipulation.
namespace utility
{
// Left over from VS2010 support, remains to avoid breaking.
typedef std::chrono::seconds seconds;
/// Functions for converting to/from std::chrono::seconds to xml string.
namespace timespan
{
/// <summary>
/// Converts a timespan/interval in seconds to xml duration string as specified by
/// http://www.w3.org/TR/xmlschema-2/#duration
/// </summary>
_ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs);
/// <summary>
/// Converts an xml duration to timespan/interval in seconds
/// http://www.w3.org/TR/xmlschema-2/#duration
/// </summary>
_ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t& timespanString);
} // namespace timespan
/// Functions for Unicode string conversions.
namespace conversions
{
/// <summary>
/// Converts a UTF-16 string to a UTF-8 string.
/// </summary>
/// <param name="w">A two byte character UTF-16 string.</param>
/// <returns>A single byte character UTF-8 string.</returns>
_ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string& w);
/// <summary>
/// Converts a UTF-8 string to a UTF-16
/// </summary>
/// <param name="s">A single byte character UTF-8 string.</param>
/// <returns>A two byte character UTF-16 string.</returns>
_ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string& s);
/// <summary>
/// Converts a ASCII (us-ascii) string to a UTF-16 string.
/// </summary>
/// <param name="s">A single byte character us-ascii string.</param>
/// <returns>A two byte character UTF-16 string.</returns>
_ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string& s);
/// <summary>
/// Converts a Latin1 (iso-8859-1) string to a UTF-16 string.
/// </summary>
/// <param name="s">A single byte character UTF-8 string.</param>
/// <returns>A two byte character UTF-16 string.</returns>
_ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string& s);
/// <summary>
/// Converts a Latin1 (iso-8859-1) string to a UTF-8 string.
/// </summary>
/// <param name="s">A single byte character UTF-8 string.</param>
/// <returns>A single byte character UTF-8 string.</returns>
_ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string& s);
/// <summary>
/// Converts to a platform dependent Unicode string type.
/// </summary>
/// <param name="s">A single byte character UTF-8 string.</param>
/// <returns>A platform dependent string type.</returns>
#ifdef _UTF16_STRINGS
_ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string&& s);
#else
inline utility::string_t&& to_string_t(std::string&& s) { return std::move(s); }
#endif
/// <summary>
/// Converts to a platform dependent Unicode string type.
/// </summary>
/// <param name="s">A two byte character UTF-16 string.</param>
/// <returns>A platform dependent string type.</returns>
#ifdef _UTF16_STRINGS
inline utility::string_t&& to_string_t(utf16string&& s) { return std::move(s); }
#else
_ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string&& s);
#endif
/// <summary>
/// Converts to a platform dependent Unicode string type.
/// </summary>
/// <param name="s">A single byte character UTF-8 string.</param>
/// <returns>A platform dependent string type.</returns>
#ifdef _UTF16_STRINGS
_ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string& s);
#else
inline const utility::string_t& to_string_t(const std::string& s) { return s; }
#endif
/// <summary>
/// Converts to a platform dependent Unicode string type.
/// </summary>
/// <param name="s">A two byte character UTF-16 string.</param>
/// <returns>A platform dependent string type.</returns>
#ifdef _UTF16_STRINGS
inline const utility::string_t& to_string_t(const utf16string& s) { return s; }
#else
_ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string& s);
#endif
/// <summary>
/// Converts to a UTF-16 from string.
/// </summary>
/// <param name="value">A single byte character UTF-8 string.</param>
/// <returns>A two byte character UTF-16 string.</returns>
_ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string& value);
/// <summary>
/// Converts to a UTF-16 from string.
/// </summary>
/// <param name="value">A two byte character UTF-16 string.</param>
/// <returns>A two byte character UTF-16 string.</returns>
inline const utf16string& to_utf16string(const utf16string& value) { return value; }
/// <summary>
/// Converts to a UTF-16 from string.
/// </summary>
/// <param name="value">A two byte character UTF-16 string.</param>
/// <returns>A two byte character UTF-16 string.</returns>
inline utf16string&& to_utf16string(utf16string&& value) { return std::move(value); }
/// <summary>
/// Converts to a UTF-8 string.
/// </summary>
/// <param name="value">A single byte character UTF-8 string.</param>
/// <returns>A single byte character UTF-8 string.</returns>
inline std::string&& to_utf8string(std::string&& value) { return std::move(value); }
/// <summary>
/// Converts to a UTF-8 string.
/// </summary>
/// <param name="value">A single byte character UTF-8 string.</param>
/// <returns>A single byte character UTF-8 string.</returns>
inline const std::string& to_utf8string(const std::string& value) { return value; }
/// <summary>
/// Converts to a UTF-8 string.
/// </summary>
/// <param name="value">A two byte character UTF-16 string.</param>
/// <returns>A single byte character UTF-8 string.</returns>
_ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string& value);
/// <summary>
/// Encode the given byte array into a base64 string
/// </summary>
_ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector<unsigned char>& data);
/// <summary>
/// Encode the given 8-byte integer into a base64 string
/// </summary>
_ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data);
/// <summary>
/// Decode the given base64 string to a byte array
/// </summary>
_ASYNCRTIMP std::vector<unsigned char> __cdecl from_base64(const utility::string_t& str);
template<typename Source>
CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if "
"locale support is required.")
utility::string_t print_string(const Source& val, const std::locale& loc = std::locale())
{
utility::ostringstream_t oss;
oss.imbue(loc);
oss << val;
if (oss.bad())
{
throw std::bad_cast();
}
return oss.str();
}
CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if "
"locale support is required.")
inline utility::string_t print_string(const utility::string_t& val) { return val; }
namespace details
{
#if defined(__ANDROID__)
template<class T>
inline std::string to_string(const T t)
{
std::ostringstream os;
os.imbue(std::locale::classic());
os << t;
return os.str();
}
#endif
template<class T>
inline utility::string_t to_string_t(const T t)
{
#ifdef _UTF16_STRINGS
using std::to_wstring;
return to_wstring(t);
#else
#if !defined(__ANDROID__)
using std::to_string;
#endif
return to_string(t);
#endif
}
template<typename Source>
utility::string_t print_string(const Source& val)
{
utility::ostringstream_t oss;
oss.imbue(std::locale::classic());
oss << val;
if (oss.bad())
{
throw std::bad_cast();
}
return oss.str();
}
inline const utility::string_t& print_string(const utility::string_t& val) { return val; }
template<typename Source>
utf8string print_utf8string(const Source& val)
{
return conversions::to_utf8string(print_string(val));
}
inline const utf8string& print_utf8string(const utf8string& val) { return val; }
template<typename Target>
Target scan_string(const utility::string_t& str)
{
Target t;
utility::istringstream_t iss(str);
iss.imbue(std::locale::classic());
iss >> t;
if (iss.bad())
{
throw std::bad_cast();
}
return t;
}
inline const utility::string_t& scan_string(const utility::string_t& str) { return str; }
} // namespace details
template<typename Target>
CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if "
"locale support is required.")
Target scan_string(const utility::string_t& str, const std::locale& loc = std::locale())
{
Target t;
utility::istringstream_t iss(str);
iss.imbue(loc);
iss >> t;
if (iss.bad())
{
throw std::bad_cast();
}
return t;
}
CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if "
"locale support is required.")
inline utility::string_t scan_string(const utility::string_t& str) { return str; }
} // namespace conversions
namespace details
{
/// <summary>
/// Cross platform RAII container for setting thread local locale.
/// </summary>
class scoped_c_thread_locale
{
public:
_ASYNCRTIMP scoped_c_thread_locale();
_ASYNCRTIMP ~scoped_c_thread_locale();
#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269
#ifdef _WIN32
typedef _locale_t xplat_locale;
#else
typedef locale_t xplat_locale;
#endif
static _ASYNCRTIMP xplat_locale __cdecl c_locale();
#endif
private:
#ifdef _WIN32
std::string m_prevLocale;
int m_prevThreadSetting;
#elif !(defined(ANDROID) || defined(__ANDROID__))
locale_t m_prevLocale;
#endif
scoped_c_thread_locale(const scoped_c_thread_locale&);
scoped_c_thread_locale& operator=(const scoped_c_thread_locale&);
};
/// <summary>
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
/// taking global lock for performance reasons.
/// </summary>
inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT
{ // test if uch is an alnum character
// special casing char to avoid branches
// clang-format off
static CPPREST_CONSTEXPR bool is_alnum_table[UCHAR_MAX + 1] = {
/* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */
/* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */
/* 4X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */
/* 5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
/* 6X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */
/* 7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
/* non-ASCII values initialized to 0 */
};
// clang-format on
return (is_alnum_table[uch]);
}
/// <summary>
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
/// taking global lock for performance reasons.
/// </summary>
inline bool __cdecl is_alnum(const char ch) CPPREST_NOEXCEPT { return (is_alnum(static_cast<unsigned char>(ch))); }
/// <summary>
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
/// taking global lock for performance reasons.
/// </summary>
template<class Elem>
inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT
{
// assumes 'x' == L'x' for the ASCII range
typedef typename std::make_unsigned<Elem>::type UElem;
const auto uch = static_cast<UElem>(ch);
return (uch <= static_cast<UElem>('z') && is_alnum(static_cast<unsigned char>(uch)));
}
/// <summary>
/// Simplistic implementation of make_unique. A better implementation would be based on variadic templates
/// and therefore not be compatible with Dev10.
/// </summary>
template<typename _Type>
std::unique_ptr<_Type> make_unique()
{
return std::unique_ptr<_Type>(new _Type());
}
template<typename _Type, typename _Arg1>
std::unique_ptr<_Type> make_unique(_Arg1&& arg1)
{
return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1)));
}
template<typename _Type, typename _Arg1, typename _Arg2>
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2)
{
return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2)));
}
template<typename _Type, typename _Arg1, typename _Arg2, typename _Arg3>
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3)
{
return std::unique_ptr<_Type>(
new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3)));
}
template<typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4>
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4)
{
return std::unique_ptr<_Type>(new _Type(
std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4)));
}
template<typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4, typename _Arg5>
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5)
{
return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1),
std::forward<_Arg2>(arg2),
std::forward<_Arg3>(arg3),
std::forward<_Arg4>(arg4),
std::forward<_Arg5>(arg5)));
}
template<typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4, typename _Arg5, typename _Arg6>
std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4, _Arg5&& arg5, _Arg6&& arg6)
{
return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1),
std::forward<_Arg2>(arg2),
std::forward<_Arg3>(arg3),
std::forward<_Arg4>(arg4),
std::forward<_Arg5>(arg5),
std::forward<_Arg6>(arg6)));
}
/// <summary>
/// Cross platform utility function for performing case insensitive string equality comparison.
/// </summary>
/// <param name="left">First string to compare.</param>
/// <param name="right">Second strong to compare.</param>
/// <returns>true if the strings are equivalent, false otherwise</returns>
_ASYNCRTIMP bool __cdecl str_iequal(const std::string& left, const std::string& right) CPPREST_NOEXCEPT;
/// <summary>
/// Cross platform utility function for performing case insensitive string equality comparison.
/// </summary>
/// <param name="left">First string to compare.</param>
/// <param name="right">Second strong to compare.</param>
/// <returns>true if the strings are equivalent, false otherwise</returns>
_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT;
/// <summary>
/// Cross platform utility function for performing case insensitive string less-than comparison.
/// </summary>
/// <param name="left">First string to compare.</param>
/// <param name="right">Second strong to compare.</param>
/// <returns>true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise,
/// false.</returns>
_ASYNCRTIMP bool __cdecl str_iless(const std::string& left, const std::string& right) CPPREST_NOEXCEPT;
/// <summary>
/// Cross platform utility function for performing case insensitive string less-than comparison.
/// </summary>
/// <param name="left">First string to compare.</param>
/// <param name="right">Second strong to compare.</param>
/// <returns>true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise,
/// false.</returns>
_ASYNCRTIMP bool __cdecl str_iless(const std::wstring& left, const std::wstring& right) CPPREST_NOEXCEPT;
/// <summary>
/// Convert a string to lowercase in place.
/// </summary>
/// <param name="target">The string to convert to lowercase.</param>
_ASYNCRTIMP void __cdecl inplace_tolower(std::string& target) CPPREST_NOEXCEPT;
/// <summary>
/// Convert a string to lowercase in place.
/// </summary>
/// <param name="target">The string to convert to lowercase.</param>
_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring& target) CPPREST_NOEXCEPT;
#ifdef _WIN32
/// <summary>
/// Category error type for Windows OS errors.
/// </summary>
class windows_category_impl : public std::error_category
{
public:
virtual const char* name() const CPPREST_NOEXCEPT { return "windows"; }
virtual std::string message(int errorCode) const CPPREST_NOEXCEPT;
virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT;
};
/// <summary>
/// Gets the one global instance of the windows error category.
/// </summary>
/// </returns>An error category instance.</returns>
_ASYNCRTIMP const std::error_category& __cdecl windows_category();
#else
/// <summary>
/// Gets the one global instance of the linux error category.
/// </summary>
/// </returns>An error category instance.</returns>
_ASYNCRTIMP const std::error_category& __cdecl linux_category();
#endif
/// <summary>
/// Gets the one global instance of the current platform's error category.
/// </summary>
_ASYNCRTIMP const std::error_category& __cdecl platform_category();
/// <summary>
/// Creates an instance of std::system_error from a OS error code.
/// </summary>
inline std::system_error __cdecl create_system_error(unsigned long errorCode)
{
std::error_code code((int)errorCode, platform_category());
return std::system_error(code, code.message());
}
/// <summary>
/// Creates a std::error_code from a OS error code.
/// </summary>
inline std::error_code __cdecl create_error_code(unsigned long errorCode)
{
return std::error_code((int)errorCode, platform_category());
}
/// <summary>
/// Creates the corresponding error message from a OS error code.
/// </summary>
inline utility::string_t __cdecl create_error_message(unsigned long errorCode)
{
return utility::conversions::to_string_t(create_error_code(errorCode).message());
}
} // namespace details
class datetime
{
public:
typedef uint64_t interval_type;
/// <summary>
/// Defines the supported date and time string formats.
/// </summary>
enum date_format
{
RFC_1123,
ISO_8601
};
/// <summary>
/// Returns the current UTC time.
/// </summary>
static _ASYNCRTIMP datetime __cdecl utc_now();
/// <summary>
/// An invalid UTC timestamp value.
/// </summary>
enum : interval_type
{
utc_timestamp_invalid = static_cast<interval_type>(-1)
};
/// <summary>
/// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00.
/// If time is before epoch, utc_timestamp_invalid is returned.
/// </summary>
static interval_type utc_timestamp()
{
const auto seconds = utc_now().to_interval() / _secondTicks;
if (seconds >= 11644473600LL)
{
return seconds - 11644473600LL;
}
else
{
return utc_timestamp_invalid;
}
}
datetime() : m_interval(0) {}
/// <summary>
/// Creates <c>datetime</c> from a string representing time in UTC in RFC 1123 format.
/// </summary>
/// <returns>Returns a <c>datetime</c> of zero if not successful.</returns>
static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123);
/// <summary>
/// Returns a string representation of the <c>datetime</c>.
/// </summary>
_ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const;
/// <summary>
/// Returns the integral time value.
/// </summary>
interval_type to_interval() const { return m_interval; }
datetime operator-(interval_type value) const { return datetime(m_interval - value); }
datetime operator+(interval_type value) const { return datetime(m_interval + value); }
bool operator==(datetime dt) const { return m_interval == dt.m_interval; }
bool operator!=(const datetime& dt) const { return !(*this == dt); }
static interval_type from_milliseconds(unsigned int milliseconds) { return milliseconds * _msTicks; }
static interval_type from_seconds(unsigned int seconds) { return seconds * _secondTicks; }
static interval_type from_minutes(unsigned int minutes) { return minutes * _minuteTicks; }
static interval_type from_hours(unsigned int hours) { return hours * _hourTicks; }
static interval_type from_days(unsigned int days) { return days * _dayTicks; }
bool is_initialized() const { return m_interval != 0; }
private:
friend int operator-(datetime t1, datetime t2);
static const interval_type _msTicks = static_cast<interval_type>(10000);
static const interval_type _secondTicks = 1000 * _msTicks;
static const interval_type _minuteTicks = 60 * _secondTicks;
static const interval_type _hourTicks = 60 * 60 * _secondTicks;
static const interval_type _dayTicks = 24 * 60 * 60 * _secondTicks;
// Private constructor. Use static methods to create an instance.
datetime(interval_type interval) : m_interval(interval) {}
// Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns.
interval_type m_interval;
};
inline int operator-(datetime t1, datetime t2)
{
auto diff = (t1.m_interval - t2.m_interval);
// Round it down to seconds
diff /= 10 * 1000 * 1000;
return static_cast<int>(diff);
}
/// <summary>
/// Nonce string generator class.
/// </summary>
class nonce_generator
{
public:
/// <summary>
/// Define default nonce length.
/// </summary>
enum
{
default_length = 32
};
/// <summary>
/// Nonce generator constructor.
/// </summary>
/// <param name="length">Length of the generated nonce string.</param>
nonce_generator(int length = default_length)
: m_random(static_cast<unsigned int>(utility::datetime::utc_timestamp())), m_length(length)
{
}
/// <summary>
/// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9).
/// Length of the generated string is set by length().
/// </summary>
/// <returns>The generated nonce string.</returns>
_ASYNCRTIMP utility::string_t generate();
/// <summary>
/// Get length of generated nonce string.
/// </summary>
/// <returns>Nonce string length.</returns>
int length() const { return m_length; }
/// <summary>
/// Set length of the generated nonce string.
/// </summary>
/// <param name="length">Lenght of nonce string.</param>
void set_length(int length) { m_length = length; }
private:
std::mt19937 m_random;
int m_length;
};
} // namespace utility

View file

@ -0,0 +1,391 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Protocol independent support for URIs.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include "cpprest/asyncrt_utils.h"
#include "cpprest/details/basic_types.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
namespace web
{
namespace details
{
struct uri_components
{
uri_components() : m_path(_XPLATSTR("/")), m_port(-1) {}
uri_components(const uri_components&) = default;
uri_components& operator=(const uri_components&) = default;
// This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped.
uri_components(uri_components&& other) CPPREST_NOEXCEPT : m_scheme(std::move(other.m_scheme)),
m_host(std::move(other.m_host)),
m_user_info(std::move(other.m_user_info)),
m_path(std::move(other.m_path)),
m_query(std::move(other.m_query)),
m_fragment(std::move(other.m_fragment)),
m_port(other.m_port)
{
}
// This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped.
uri_components& operator=(uri_components&& other) CPPREST_NOEXCEPT
{
if (this != &other)
{
m_scheme = std::move(other.m_scheme);
m_host = std::move(other.m_host);
m_user_info = std::move(other.m_user_info);
m_path = std::move(other.m_path);
m_query = std::move(other.m_query);
m_fragment = std::move(other.m_fragment);
m_port = other.m_port;
}
return *this;
}
_ASYNCRTIMP utility::string_t join();
utility::string_t m_scheme;
utility::string_t m_host;
utility::string_t m_user_info;
utility::string_t m_path;
utility::string_t m_query;
utility::string_t m_fragment;
int m_port;
};
} // namespace details
/// <summary>
/// A single exception type to represent errors in parsing, encoding, and decoding URIs.
/// </summary>
class uri_exception : public std::exception
{
public:
uri_exception(std::string msg) : m_msg(std::move(msg)) {}
~uri_exception() CPPREST_NOEXCEPT {}
const char* what() const CPPREST_NOEXCEPT { return m_msg.c_str(); }
private:
std::string m_msg;
};
/// <summary>
/// A flexible, protocol independent URI implementation.
///
/// URI instances are immutable. Querying the various fields on an empty URI will return empty strings. Querying
/// various diagnostic members on an empty URI will return false.
/// </summary>
/// <remarks>
/// This implementation accepts both URIs ('http://msn.com/path') and URI relative-references
/// ('/path?query#frag').
///
/// This implementation does not provide any scheme-specific handling -- an example of this
/// would be the following: 'http://path1/path'. This is a valid URI, but it's not a valid
/// http-uri -- that is, it's syntactically correct but does not conform to the requirements
/// of the http scheme (http requires a host).
/// We could provide this by allowing a pluggable 'scheme' policy-class, which would provide
/// extra capability for validating and canonicalizing a URI according to scheme, and would
/// introduce a layer of type-safety for URIs of differing schemes, and thus differing semantics.
///
/// One issue with implementing a scheme-independent URI facility is that of comparing for equality.
/// For instance, these URIs are considered equal 'http://msn.com', 'http://msn.com:80'. That is --
/// the 'default' port can be either omitted or explicit. Since we don't have a way to map a scheme
/// to it's default port, we don't have a way to know these are equal. This is just one of a class of
/// issues with regard to scheme-specific behavior.
/// </remarks>
class uri
{
public:
/// <summary>
/// The various components of a URI. This enum is used to indicate which
/// URI component is being encoded to the encode_uri_component. This allows
/// specific encoding to be performed.
///
/// Scheme and port don't allow '%' so they don't need to be encoded.
/// </summary>
class components
{
public:
enum component
{
user_info,
host,
path,
query,
fragment,
full_uri
};
};
/// <summary>
/// Encodes a URI component according to RFC 3986.
/// Note if a full URI is specified instead of an individual URI component all
/// characters not in the unreserved set are escaped.
/// </summary>
/// <param name="raw">The URI as a string.</param>
/// <returns>The encoded string.</returns>
_ASYNCRTIMP static utility::string_t __cdecl encode_uri(const utility::string_t& raw,
uri::components::component = components::full_uri);
/// <summary>
/// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their
/// hexadecimal representation.
/// </summary>
/// <returns>The encoded string.</returns>
_ASYNCRTIMP static utility::string_t __cdecl encode_data_string(const utility::string_t& data);
/// <summary>
/// Decodes an encoded string.
/// </summary>
/// <param name="encoded">The URI as a string.</param>
/// <returns>The decoded string.</returns>
_ASYNCRTIMP static utility::string_t __cdecl decode(const utility::string_t& encoded);
/// <summary>
/// Splits a path into its hierarchical components.
/// </summary>
/// <param name="path">The path as a string</param>
/// <returns>A <c>std::vector&lt;utility::string_t&gt;</c> containing the segments in the path.</returns>
_ASYNCRTIMP static std::vector<utility::string_t> __cdecl split_path(const utility::string_t& path);
/// <summary>
/// Splits a query into its key-value components.
/// </summary>
/// <param name="query">The query string</param>
/// <returns>A <c>std::map&lt;utility::string_t, utility::string_t&gt;</c> containing the key-value components of
/// the query.</returns>
_ASYNCRTIMP static std::map<utility::string_t, utility::string_t> __cdecl split_query(
const utility::string_t& query);
/// <summary>
/// Validates a string as a URI.
/// </summary>
/// <remarks>
/// This function accepts both uris ('http://msn.com') and uri relative-references ('path1/path2?query').
/// </remarks>
/// <param name="uri_string">The URI string to be validated.</param>
/// <returns><c>true</c> if the given string represents a valid URI, <c>false</c> otherwise.</returns>
_ASYNCRTIMP static bool __cdecl validate(const utility::string_t& uri_string);
/// <summary>
/// Creates an empty uri
/// </summary>
uri() : m_uri(_XPLATSTR("/")) {}
/// <summary>
/// Creates a URI from the given encoded string. This will throw an exception if the string
/// does not contain a valid URI. Use uri::validate if processing user-input.
/// </summary>
/// <param name="uri_string">A pointer to an encoded string to create the URI instance.</param>
_ASYNCRTIMP uri(const utility::char_t* uri_string);
/// <summary>
/// Creates a URI from the given encoded string. This will throw an exception if the string
/// does not contain a valid URI. Use uri::validate if processing user-input.
/// </summary>
/// <param name="uri_string">An encoded URI string to create the URI instance.</param>
_ASYNCRTIMP uri(const utility::string_t& uri_string);
/// <summary>
/// Copy constructor.
/// </summary>
uri(const uri&) = default;
/// <summary>
/// Copy assignment operator.
/// </summary>
uri& operator=(const uri&) = default;
/// <summary>
/// Move constructor.
/// </summary>
// This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped.
uri(uri&& other) CPPREST_NOEXCEPT : m_uri(std::move(other.m_uri)), m_components(std::move(other.m_components)) {}
/// <summary>
/// Move assignment operator
/// </summary>
// This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped.
uri& operator=(uri&& other) CPPREST_NOEXCEPT
{
if (this != &other)
{
m_uri = std::move(other.m_uri);
m_components = std::move(other.m_components);
}
return *this;
}
/// <summary>
/// Get the scheme component of the URI as an encoded string.
/// </summary>
/// <returns>The URI scheme as a string.</returns>
const utility::string_t& scheme() const { return m_components.m_scheme; }
/// <summary>
/// Get the user information component of the URI as an encoded string.
/// </summary>
/// <returns>The URI user information as a string.</returns>
const utility::string_t& user_info() const { return m_components.m_user_info; }
/// <summary>
/// Get the host component of the URI as an encoded string.
/// </summary>
/// <returns>The URI host as a string.</returns>
const utility::string_t& host() const { return m_components.m_host; }
/// <summary>
/// Get the port component of the URI. Returns -1 if no port is specified.
/// </summary>
/// <returns>The URI port as an integer.</returns>
int port() const { return m_components.m_port; }
/// <summary>
/// Get the path component of the URI as an encoded string.
/// </summary>
/// <returns>The URI path as a string.</returns>
const utility::string_t& path() const { return m_components.m_path; }
/// <summary>
/// Get the query component of the URI as an encoded string.
/// </summary>
/// <returns>The URI query as a string.</returns>
const utility::string_t& query() const { return m_components.m_query; }
/// <summary>
/// Get the fragment component of the URI as an encoded string.
/// </summary>
/// <returns>The URI fragment as a string.</returns>
const utility::string_t& fragment() const { return m_components.m_fragment; }
/// <summary>
/// Creates a new uri object with the same authority portion as this one, omitting the resource and query portions.
/// </summary>
/// <returns>The new uri object with the same authority.</returns>
_ASYNCRTIMP uri authority() const;
/// <summary>
/// Gets the path, query, and fragment portion of this uri, which may be empty.
/// </summary>
/// <returns>The new URI object with the path, query and fragment portion of this URI.</returns>
_ASYNCRTIMP uri resource() const;
/// <summary>
/// An empty URI specifies no components, and serves as a default value
/// </summary>
bool is_empty() const { return this->m_uri.empty() || this->m_uri == _XPLATSTR("/"); }
/// <summary>
/// A loopback URI is one which refers to a hostname or ip address with meaning only on the local machine.
/// </summary>
/// <remarks>
/// Examples include "localhost", or ip addresses in the loopback range (127.0.0.0/24).
/// </remarks>
/// <returns><c>true</c> if this URI references the local host, <c>false</c> otherwise.</returns>
bool is_host_loopback() const
{
return !is_empty() &&
((host() == _XPLATSTR("localhost")) || (host().size() > 4 && host().substr(0, 4) == _XPLATSTR("127.")));
}
/// <summary>
/// A wildcard URI is one which refers to all hostnames that resolve to the local machine (using the * or +)
/// </summary>
/// <example>
/// http://*:80
/// </example>
bool is_host_wildcard() const
{
return !is_empty() && (this->host() == _XPLATSTR("*") || this->host() == _XPLATSTR("+"));
}
/// <summary>
/// A portable URI is one with a hostname that can be resolved globally (used from another machine).
/// </summary>
/// <returns><c>true</c> if this URI can be resolved globally (used from another machine), <c>false</c>
/// otherwise.</returns> <remarks> The hostname "localhost" is a reserved name that is guaranteed to resolve to the
/// local machine, and cannot be used for inter-machine communication. Likewise the hostnames "*" and "+" on Windows
/// represent wildcards, and do not map to a resolvable address.
/// </remarks>
bool is_host_portable() const { return !(is_empty() || is_host_loopback() || is_host_wildcard()); }
/// <summary>
/// A default port is one where the port is unspecified, and will be determined by the operating system.
/// The choice of default port may be dictated by the scheme (http -> 80) or not.
/// </summary>
/// <returns><c>true</c> if this URI instance has a default port, <c>false</c> otherwise.</returns>
bool is_port_default() const { return !is_empty() && this->port() == 0; }
/// <summary>
/// An "authority" URI is one with only a scheme, optional userinfo, hostname, and (optional) port.
/// </summary>
/// <returns><c>true</c> if this is an "authority" URI, <c>false</c> otherwise.</returns>
bool is_authority() const { return !is_empty() && is_path_empty() && query().empty() && fragment().empty(); }
/// <summary>
/// Returns whether the other URI has the same authority as this one
/// </summary>
/// <param name="other">The URI to compare the authority with.</param>
/// <returns><c>true</c> if both the URI's have the same authority, <c>false</c> otherwise.</returns>
bool has_same_authority(const uri& other) const { return !is_empty() && this->authority() == other.authority(); }
/// <summary>
/// Returns whether the path portion of this URI is empty
/// </summary>
/// <returns><c>true</c> if the path portion of this URI is empty, <c>false</c> otherwise.</returns>
bool is_path_empty() const { return path().empty() || path() == _XPLATSTR("/"); }
/// <summary>
/// Returns the full (encoded) URI as a string.
/// </summary>
/// <returns>The full encoded URI string.</returns>
utility::string_t to_string() const { return m_uri; }
/// <summary>
/// Returns an URI resolved against <c>this</c> as the base URI
/// according to RFC3986, Section 5 (https://tools.ietf.org/html/rfc3986#section-5).
/// </summary>
/// <param name="relativeUri">The relative URI to be resolved against <c>this</c> as base.</param>
/// <returns>The new resolved URI string.</returns>
_ASYNCRTIMP utility::string_t resolve_uri(const utility::string_t& relativeUri) const;
_ASYNCRTIMP bool operator==(const uri& other) const;
bool operator<(const uri& other) const { return m_uri < other.m_uri; }
bool operator!=(const uri& other) const { return !(this->operator==(other)); }
private:
friend class uri_builder;
/// <summary>
/// Creates a URI from the given URI components.
/// </summary>
/// <param name="components">A URI components object to create the URI instance.</param>
_ASYNCRTIMP uri(const details::uri_components& components);
// Used by uri_builder
static utility::string_t __cdecl encode_query_impl(const utf8string& raw);
utility::string_t m_uri;
details::uri_components m_components;
};
} // namespace web

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,131 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Platform-dependent type definitions
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include "cpprest/details/cpprest_compat.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#ifndef _WIN32
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>
#else
#include <cstdint>
#endif
#include "cpprest/details/SafeInt3.hpp"
namespace utility
{
#ifdef _WIN32
#define _UTF16_STRINGS
#endif
// We should be using a 64-bit size type for most situations that do
// not involve specifying the size of a memory allocation or buffer.
typedef uint64_t size64_t;
#ifndef _WIN32
typedef uint32_t HRESULT; // Needed for PPLX
#endif
#ifdef _UTF16_STRINGS
//
// On Windows, all strings are wide
//
typedef wchar_t char_t;
typedef std::wstring string_t;
#define _XPLATSTR(x) L##x
typedef std::wostringstream ostringstream_t;
typedef std::wofstream ofstream_t;
typedef std::wostream ostream_t;
typedef std::wistream istream_t;
typedef std::wifstream ifstream_t;
typedef std::wistringstream istringstream_t;
typedef std::wstringstream stringstream_t;
#define ucout std::wcout
#define ucin std::wcin
#define ucerr std::wcerr
#else
//
// On POSIX platforms, all strings are narrow
//
typedef char char_t;
typedef std::string string_t;
#define _XPLATSTR(x) x
typedef std::ostringstream ostringstream_t;
typedef std::ofstream ofstream_t;
typedef std::ostream ostream_t;
typedef std::istream istream_t;
typedef std::ifstream ifstream_t;
typedef std::istringstream istringstream_t;
typedef std::stringstream stringstream_t;
#define ucout std::cout
#define ucin std::cin
#define ucerr std::cerr
#endif // endif _UTF16_STRINGS
#ifndef _TURN_OFF_PLATFORM_STRING
// The 'U' macro can be used to create a string or character literal of the platform type, i.e. utility::char_t.
// If you are using a library causing conflicts with 'U' macro, it can be turned off by defining the macro
// '_TURN_OFF_PLATFORM_STRING' before including the C++ REST SDK header files, and e.g. use '_XPLATSTR' instead.
#define U(x) _XPLATSTR(x)
#endif // !_TURN_OFF_PLATFORM_STRING
} // namespace utility
typedef char utf8char;
typedef std::string utf8string;
typedef std::stringstream utf8stringstream;
typedef std::ostringstream utf8ostringstream;
typedef std::ostream utf8ostream;
typedef std::istream utf8istream;
typedef std::istringstream utf8istringstream;
#ifdef _UTF16_STRINGS
typedef wchar_t utf16char;
typedef std::wstring utf16string;
typedef std::wstringstream utf16stringstream;
typedef std::wostringstream utf16ostringstream;
typedef std::wostream utf16ostream;
typedef std::wistream utf16istream;
typedef std::wistringstream utf16istringstream;
#else
typedef char16_t utf16char;
typedef std::u16string utf16string;
typedef std::basic_stringstream<utf16char> utf16stringstream;
typedef std::basic_ostringstream<utf16char> utf16ostringstream;
typedef std::basic_ostream<utf16char> utf16ostream;
typedef std::basic_istream<utf16char> utf16istream;
typedef std::basic_istringstream<utf16char> utf16istringstream;
#endif
#if defined(_WIN32)
// Include on everything except Windows Desktop ARM, unless explicitly excluded.
#if !defined(CPPREST_EXCLUDE_WEBSOCKETS)
#if defined(WINAPI_FAMILY)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && defined(_M_ARM)
#define CPPREST_EXCLUDE_WEBSOCKETS
#endif
#else
#if defined(_M_ARM)
#define CPPREST_EXCLUDE_WEBSOCKETS
#endif
#endif
#endif
#endif

View file

@ -0,0 +1,91 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Standard macros and definitions.
* This header has minimal dependency on windows headers and is safe for use in the public API
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#if defined(_WIN32)
#if _MSC_VER >= 1900
#define CPPREST_NOEXCEPT noexcept
#define CPPREST_CONSTEXPR constexpr
#else
#define CPPREST_NOEXCEPT
#define CPPREST_CONSTEXPR const
#endif // _MSC_VER >= 1900
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x)
#include <sal.h>
#else // ^^^ _WIN32 ^^^ // vvv !_WIN32 vvv
#define __declspec(x) __attribute__((x))
#define dllimport
#define novtable /* no novtable equivalent */
#define __assume(x) \
do \
{ \
if (!(x)) __builtin_unreachable(); \
} while (false)
#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x
#define CPPREST_NOEXCEPT noexcept
#define CPPREST_CONSTEXPR constexpr
#include <assert.h>
#define _ASSERTE(x) assert(x)
// No SAL on non Windows platforms
#include "cpprest/details/nosal.h"
#if !defined(__cdecl)
#if defined(cdecl)
#define __cdecl __attribute__((cdecl))
#else // ^^^ defined cdecl ^^^ // vvv !defined cdecl vvv
#define __cdecl
#endif // defined cdecl
#endif // not defined __cdecl
#if defined(__ANDROID__)
// This is needed to disable the use of __thread inside the boost library.
// Android does not support thread local storage -- if boost is included
// without this macro defined, it will create references to __tls_get_addr
// which (while able to link) will not be available at runtime and prevent
// the .so from loading.
#if not defined BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
#endif // not defined BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
#endif // defined(__ANDROID__)
#ifdef __clang__
#include <cstdio>
#endif // __clang__
#endif // _WIN32
#define _NO_ASYNCRTIMP
#ifdef _NO_ASYNCRTIMP
#define _ASYNCRTIMP
#else // ^^^ _NO_ASYNCRTIMP ^^^ // vvv !_NO_ASYNCRTIMP vvv
#ifdef _ASYNCRT_EXPORT
#define _ASYNCRTIMP __declspec(dllexport)
#else // ^^^ _ASYNCRT_EXPORT ^^^ // vvv !_ASYNCRT_EXPORT vvv
#define _ASYNCRTIMP __declspec(dllimport)
#endif // _ASYNCRT_EXPORT
#endif // _NO_ASYNCRTIMP
#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS
#define CASABLANCA_DEPRECATED(x)
#else
#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x))
#endif // CASABLANCA_DEPRECATION_NO_WARNINGS

View file

@ -0,0 +1,223 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* utility classes used by the different web:: clients
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include "cpprest/asyncrt_utils.h"
#include "cpprest/uri.h"
namespace web
{
namespace details
{
class zero_memory_deleter
{
public:
_ASYNCRTIMP void operator()(::utility::string_t* data) const;
};
typedef std::unique_ptr<::utility::string_t, zero_memory_deleter> plaintext_string;
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
#if defined(__cplusplus_winrt)
class winrt_encryption
{
public:
winrt_encryption() {}
_ASYNCRTIMP winrt_encryption(const std::wstring& data);
_ASYNCRTIMP plaintext_string decrypt() const;
private:
::pplx::task<Windows::Storage::Streams::IBuffer ^> m_buffer;
};
#else
class win32_encryption
{
public:
win32_encryption() {}
_ASYNCRTIMP win32_encryption(const std::wstring& data);
_ASYNCRTIMP ~win32_encryption();
_ASYNCRTIMP plaintext_string decrypt() const;
private:
std::vector<char> m_buffer;
size_t m_numCharacters;
};
#endif
#endif
} // namespace details
/// <summary>
/// Represents a set of user credentials (user name and password) to be used
/// for authentication.
/// </summary>
class credentials
{
public:
/// <summary>
/// Constructs an empty set of credentials without a user name or password.
/// </summary>
credentials() {}
/// <summary>
/// Constructs credentials from given user name and password.
/// </summary>
/// <param name="username">User name as a string.</param>
/// <param name="password">Password as a string.</param>
credentials(utility::string_t username, const utility::string_t& password)
: m_username(std::move(username)), m_password(password)
{
}
/// <summary>
/// The user name associated with the credentials.
/// </summary>
/// <returns>A string containing the user name.</returns>
const utility::string_t& username() const { return m_username; }
/// <summary>
/// The password for the user name associated with the credentials.
/// </summary>
/// <returns>A string containing the password.</returns>
CASABLANCA_DEPRECATED(
"This API is deprecated for security reasons to avoid unnecessary password copies stored in plaintext.")
utility::string_t password() const
{
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
return utility::string_t(*m_password.decrypt());
#else
return m_password;
#endif
}
/// <summary>
/// Checks if credentials have been set
/// </summary>
/// <returns><c>true</c> if user name and password is set, <c>false</c> otherwise.</returns>
bool is_set() const { return !m_username.empty(); }
details::plaintext_string _internal_decrypt() const
{
// Encryption APIs not supported on XP
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
return m_password.decrypt();
#else
return details::plaintext_string(new ::utility::string_t(m_password));
#endif
}
private:
::utility::string_t m_username;
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
#if defined(__cplusplus_winrt)
details::winrt_encryption m_password;
#else
details::win32_encryption m_password;
#endif
#else
::utility::string_t m_password;
#endif
};
/// <summary>
/// web_proxy represents the concept of the web proxy, which can be auto-discovered,
/// disabled, or specified explicitly by the user.
/// </summary>
class web_proxy
{
enum web_proxy_mode_internal
{
use_default_,
use_auto_discovery_,
disabled_,
user_provided_
};
public:
enum web_proxy_mode
{
use_default = use_default_,
use_auto_discovery = use_auto_discovery_,
disabled = disabled_
};
/// <summary>
/// Constructs a proxy with the default settings.
/// </summary>
web_proxy() : m_address(_XPLATSTR("")), m_mode(use_default_) {}
/// <summary>
/// Creates a proxy with specified mode.
/// </summary>
/// <param name="mode">Mode to use.</param>
web_proxy(web_proxy_mode mode) : m_address(_XPLATSTR("")), m_mode(static_cast<web_proxy_mode_internal>(mode)) {}
/// <summary>
/// Creates a proxy explicitly with provided address.
/// </summary>
/// <param name="address">Proxy URI to use.</param>
web_proxy(uri address) : m_address(address), m_mode(user_provided_) {}
/// <summary>
/// Gets this proxy's URI address. Returns an empty URI if not explicitly set by user.
/// </summary>
/// <returns>A reference to this proxy's URI.</returns>
const uri& address() const { return m_address; }
/// <summary>
/// Gets the credentials used for authentication with this proxy.
/// </summary>
/// <returns>Credentials to for this proxy.</returns>
const web::credentials& credentials() const { return m_credentials; }
/// <summary>
/// Sets the credentials to use for authentication with this proxy.
/// </summary>
/// <param name="cred">Credentials to use for this proxy.</param>
void set_credentials(web::credentials cred)
{
if (m_mode == disabled_)
{
throw std::invalid_argument("Cannot attach credentials to a disabled proxy");
}
m_credentials = std::move(cred);
}
/// <summary>
/// Checks if this proxy was constructed with default settings.
/// </summary>
/// <returns>True if default, false otherwise.</param>
bool is_default() const { return m_mode == use_default_; }
/// <summary>
/// Checks if using a proxy is disabled.
/// </summary>
/// <returns>True if disabled, false otherwise.</returns>
bool is_disabled() const { return m_mode == disabled_; }
/// <summary>
/// Checks if the auto discovery protocol, WPAD, is to be used.
/// </summary>
/// <returns>True if auto discovery enabled, false otherwise.</returns>
bool is_auto_discovery() const { return m_mode == use_auto_discovery_; }
/// <summary>
/// Checks if a proxy address is explicitly specified by the user.
/// </summary>
/// <returns>True if a proxy address was explicitly specified, false otherwise.</returns>
bool is_specified() const { return m_mode == user_provided_; }
private:
web::uri m_address;
web_proxy_mode_internal m_mode;
web::credentials m_credentials;
};
} // namespace web

1786
deps/cpprestsdk/include/cpprest/json.h vendored Normal file

File diff suppressed because it is too large Load diff

21
deps/cpprestsdk/include/cpprest/uri.h vendored Normal file
View file

@ -0,0 +1,21 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Protocol independent support for URIs.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#ifndef CASA_URI_H
#define CASA_URI_H
#include "cpprest/base_uri.h"
#include "cpprest/uri_builder.h"
#endif

View file

@ -0,0 +1,295 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Builder style class for creating URIs.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once
#include "cpprest/base_uri.h"
#include <string>
namespace web
{
/// <summary>
/// Builder for constructing URIs incrementally.
/// </summary>
class uri_builder
{
public:
/// <summary>
/// Creates a builder with an initially empty URI.
/// </summary>
uri_builder() = default;
/// <summary>
/// Creates a builder with a existing URI object.
/// </summary>
/// <param name="uri_str">Encoded string containing the URI.</param>
uri_builder(const uri& uri_str) : m_uri(uri_str.m_components) {}
/// <summary>
/// Get the scheme component of the URI as an encoded string.
/// </summary>
/// <returns>The URI scheme as a string.</returns>
const utility::string_t& scheme() const { return m_uri.m_scheme; }
/// <summary>
/// Get the user information component of the URI as an encoded string.
/// </summary>
/// <returns>The URI user information as a string.</returns>
const utility::string_t& user_info() const { return m_uri.m_user_info; }
/// <summary>
/// Get the host component of the URI as an encoded string.
/// </summary>
/// <returns>The URI host as a string.</returns>
const utility::string_t& host() const { return m_uri.m_host; }
/// <summary>
/// Get the port component of the URI. Returns -1 if no port is specified.
/// </summary>
/// <returns>The URI port as an integer.</returns>
int port() const { return m_uri.m_port; }
/// <summary>
/// Get the path component of the URI as an encoded string.
/// </summary>
/// <returns>The URI path as a string.</returns>
const utility::string_t& path() const { return m_uri.m_path; }
/// <summary>
/// Get the query component of the URI as an encoded string.
/// </summary>
/// <returns>The URI query as a string.</returns>
const utility::string_t& query() const { return m_uri.m_query; }
/// <summary>
/// Get the fragment component of the URI as an encoded string.
/// </summary>
/// <returns>The URI fragment as a string.</returns>
const utility::string_t& fragment() const { return m_uri.m_fragment; }
/// <summary>
/// Set the scheme of the URI.
/// </summary>
/// <param name="scheme">Uri scheme.</param>
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
uri_builder& set_scheme(const utility::string_t& scheme)
{
m_uri.m_scheme = scheme;
return *this;
}
/// <summary>
/// Set the user info component of the URI.
/// </summary>
/// <param name="user_info">User info as a decoded string.</param>
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
uri_builder& set_user_info(const utility::string_t& user_info, bool do_encoding = false)
{
if (do_encoding)
{
m_uri.m_user_info = uri::encode_uri(user_info, uri::components::user_info);
}
else
{
m_uri.m_user_info = user_info;
}
return *this;
}
/// <summary>
/// Set the host component of the URI.
/// </summary>
/// <param name="host">Host as a decoded string.</param>
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
uri_builder& set_host(const utility::string_t& host, bool do_encoding = false)
{
if (do_encoding)
{
m_uri.m_host = uri::encode_uri(host, uri::components::host);
}
else
{
m_uri.m_host = host;
}
return *this;
}
/// <summary>
/// Set the port component of the URI.
/// </summary>
/// <param name="port">Port as an integer.</param>
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
uri_builder& set_port(int port)
{
m_uri.m_port = port;
return *this;
}
/// <summary>
/// Set the port component of the URI.
/// </summary>
/// <param name="port">Port as a string.</param>
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
/// <remarks>When string can't be converted to an integer the port is left unchanged.</remarks>
_ASYNCRTIMP uri_builder& set_port(const utility::string_t& port);
/// <summary>
/// Set the path component of the URI.
/// </summary>
/// <param name="path">Path as a decoded string.</param>
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
uri_builder& set_path(const utility::string_t& path, bool do_encoding = false)
{
if (do_encoding)
{
m_uri.m_path = uri::encode_uri(path, uri::components::path);
}
else
{
m_uri.m_path = path;
}
return *this;
}
/// <summary>
/// Set the query component of the URI.
/// </summary>
/// <param name="query">Query as a decoded string.</param>
/// <param name="do_encoding">Specify whether apply URI encoding to the given string.</param>
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
uri_builder& set_query(const utility::string_t& query, bool do_encoding = false)
{
if (do_encoding)
{
m_uri.m_query = uri::encode_uri(query, uri::components::query);
}
else
{
m_uri.m_query = query;
}
return *this;
}
/// <summary>
/// Set the fragment component of the URI.
/// </summary>
/// <param name="fragment">Fragment as a decoded string.</param>
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
/// <returns>A reference to this <c>uri_builder</c> to support chaining.</returns>
uri_builder& set_fragment(const utility::string_t& fragment, bool do_encoding = false)
{
if (do_encoding)
{
m_uri.m_fragment = uri::encode_uri(fragment, uri::components::fragment);
}
else
{
m_uri.m_fragment = fragment;
}
return *this;
}
/// <summary>
/// Clears all components of the underlying URI in this uri_builder.
/// </summary>
void clear() { m_uri = details::uri_components(); }
/// <summary>
/// Appends another path to the path of this uri_builder.
/// </summary>
/// <param name="path">Path to append as a already encoded string.</param>
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
/// <returns>A reference to this uri_builder to support chaining.</returns>
_ASYNCRTIMP uri_builder& append_path(const utility::string_t& path, bool do_encoding = false);
/// <summary>
/// Appends the raw contents of the path argument to the path of this uri_builder with no separator de-duplication.
/// </summary>
/// <remarks>
/// The path argument is appended after adding a '/' separator without regards to the contents of path. If an empty
/// string is provided, this function will immediately return without changes to the stored path value. For example:
/// if the current contents are "/abc" and path="/xyz", the result will be "/abc//xyz".
/// </remarks>
/// <param name="path">Path to append as a already encoded string.</param>
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
/// <returns>A reference to this uri_builder to support chaining.</returns>
_ASYNCRTIMP uri_builder& append_path_raw(const utility::string_t& path, bool do_encoding = false);
/// <summary>
/// Appends another query to the query of this uri_builder.
/// </summary>
/// <param name="query">Query to append as a decoded string.</param>
/// <param name="do_encoding">Specify whether to apply URI encoding to the given string.</param>
/// <returns>A reference to this uri_builder to support chaining.</returns>
_ASYNCRTIMP uri_builder& append_query(const utility::string_t& query, bool do_encoding = false);
/// <summary>
/// Appends an relative uri (Path, Query and fragment) at the end of the current uri.
/// </summary>
/// <param name="relative_uri">The relative uri to append.</param>
/// <returns>A reference to this uri_builder to support chaining.</returns>
_ASYNCRTIMP uri_builder& append(const uri& relative_uri);
/// <summary>
/// Appends another query to the query of this uri_builder, encoding it first. This overload is useful when building
/// a query segment of the form "element=10", where the right hand side of the query is stored as a type other than
/// a string, for instance, an integral type.
/// </summary>
/// <param name="name">The name portion of the query string</param>
/// <param name="value">The value portion of the query string</param>
/// <returns>A reference to this uri_builder to support chaining.</returns>
template<typename T>
uri_builder& append_query(const utility::string_t& name, const T& value, bool do_encoding = true)
{
if (do_encoding)
append_query_encode_impl(name, utility::conversions::details::print_utf8string(value));
else
append_query_no_encode_impl(name, utility::conversions::details::print_string(value));
return *this;
}
/// <summary>
/// Combine and validate the URI components into a encoded string. An exception will be thrown if the URI is
/// invalid.
/// </summary>
/// <returns>The created URI as a string.</returns>
_ASYNCRTIMP utility::string_t to_string() const;
/// <summary>
/// Combine and validate the URI components into a URI class instance. An exception will be thrown if the URI is
/// invalid.
/// </summary>
/// <returns>The create URI as a URI class instance.</returns>
_ASYNCRTIMP uri to_uri() const;
/// <summary>
/// Validate the generated URI from all existing components of this uri_builder.
/// </summary>
/// <returns>Whether the URI is valid.</returns>
_ASYNCRTIMP bool is_valid();
private:
_ASYNCRTIMP void append_query_encode_impl(const utility::string_t& name, const utf8string& value);
_ASYNCRTIMP void append_query_no_encode_impl(const utility::string_t& name, const utility::string_t& value);
details::uri_components m_uri;
};
} // namespace web

View file

@ -0,0 +1,10 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
*/
#define CPPREST_VERSION_MINOR 10
#define CPPREST_VERSION_MAJOR 2
#define CPPREST_VERSION_REVISION 13
#define CPPREST_VERSION (CPPREST_VERSION_MAJOR * 100000 + CPPREST_VERSION_MINOR * 100 + CPPREST_VERSION_REVISION)

25
deps/cpprestsdk/license.txt vendored Normal file
View file

@ -0,0 +1,25 @@
C++ REST SDK
The MIT License (MIT)
Copyright (c) Microsoft Corporation
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1
deps/cpprestsdk/pch.cpp vendored Normal file
View file

@ -0,0 +1 @@
#include "pch.h"

34
deps/cpprestsdk/pch.h vendored Normal file
View file

@ -0,0 +1,34 @@
#include <winrt/base.h>
#include <Windows.h>
#include <dxgi1_3.h>
#include <d3d11_2.h>
#include <d2d1_3.h>
#include <d2d1_3helper.h>
#include <d2d1helper.h>
#include <dwrite.h>
#include <dcomp.h>
#include <dwmapi.h>
#include <Shobjidl.h>
#include <Shlwapi.h>
#include <string>
#include <algorithm>
#include <chrono>
#include <mutex>
#include <thread>
#include <functional>
#include <condition_variable>
#include <stdexcept>
#include <tuple>
#include <unordered_set>
#include <string>
#include <vector>
// cpprestsdk headers
#include "cpprest/details/basic_types.h"
#include "cpprest/details/cpprest_compat.h"
#include "cpprest/version.h"
// json
#include "cpprest/json.h"
// utilities
#include "cpprest/asyncrt_utils.h"
#include "cpprest/details/web_utilities.h"

475
deps/cpprestsdk/src/json/json.cpp vendored Normal file
View file

@ -0,0 +1,475 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: JSON parser and writer
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include "pch.h"
using namespace web;
bool json::details::g_keep_json_object_unsorted = false;
void json::keep_object_element_order(bool keep_order) { json::details::g_keep_json_object_unsorted = keep_order; }
utility::ostream_t& web::json::operator<<(utility::ostream_t& os, const web::json::value& val)
{
val.serialize(os);
return os;
}
utility::istream_t& web::json::operator>>(utility::istream_t& is, json::value& val)
{
val = json::value::parse(is);
return is;
}
web::json::value::value()
: m_value(utility::details::make_unique<web::json::details::_Null>())
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::Null)
#endif
{
}
web::json::value::value(int32_t value)
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::Number)
#endif
{
}
web::json::value::value(uint32_t value)
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::Number)
#endif
{
}
web::json::value::value(int64_t value)
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::Number)
#endif
{
}
web::json::value::value(uint64_t value)
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::Number)
#endif
{
}
web::json::value::value(double value)
: m_value(utility::details::make_unique<web::json::details::_Number>(value))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::Number)
#endif
{
}
web::json::value::value(bool value)
: m_value(utility::details::make_unique<web::json::details::_Boolean>(value))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::Boolean)
#endif
{
}
web::json::value::value(utility::string_t value)
: m_value(utility::details::make_unique<web::json::details::_String>(std::move(value)))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::String)
#endif
{
}
web::json::value::value(utility::string_t value, bool has_escape_chars)
: m_value(utility::details::make_unique<web::json::details::_String>(std::move(value), has_escape_chars))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::String)
#endif
{
}
web::json::value::value(const utility::char_t* value)
: m_value(utility::details::make_unique<web::json::details::_String>(value))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::String)
#endif
{
}
web::json::value::value(const utility::char_t* value, bool has_escape_chars)
: m_value(utility::details::make_unique<web::json::details::_String>(utility::string_t(value), has_escape_chars))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(value::String)
#endif
{
}
web::json::value::value(const value& other)
: m_value(other.m_value->_copy_value())
#ifdef ENABLE_JSON_VALUE_VISUALIZER
, m_kind(other.m_kind)
#endif
{
}
web::json::value& web::json::value::operator=(const value& other)
{
if (this != &other)
{
m_value = std::unique_ptr<details::_Value>(other.m_value->_copy_value());
#ifdef ENABLE_JSON_VALUE_VISUALIZER
m_kind = other.m_kind;
#endif
}
return *this;
}
web::json::value::value(value&& other) CPPREST_NOEXCEPT : m_value(std::move(other.m_value))
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
m_kind(other.m_kind)
#endif
{
}
web::json::value& web::json::value::operator=(web::json::value&& other) CPPREST_NOEXCEPT
{
if (this != &other)
{
m_value.swap(other.m_value);
#ifdef ENABLE_JSON_VALUE_VISUALIZER
m_kind = other.m_kind;
#endif
}
return *this;
}
web::json::value web::json::value::null() { return web::json::value(); }
web::json::value web::json::value::number(double value) { return web::json::value(value); }
web::json::value web::json::value::number(int32_t value) { return web::json::value(value); }
web::json::value web::json::value::number(uint32_t value) { return web::json::value(value); }
web::json::value web::json::value::number(int64_t value) { return web::json::value(value); }
web::json::value web::json::value::number(uint64_t value) { return web::json::value(value); }
web::json::value web::json::value::boolean(bool value) { return web::json::value(value); }
web::json::value web::json::value::string(utility::string_t value)
{
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_String>(std::move(value));
return web::json::value(std::move(ptr)
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
value::String
#endif
);
}
web::json::value web::json::value::string(utility::string_t value, bool has_escape_chars)
{
std::unique_ptr<details::_Value> ptr =
utility::details::make_unique<details::_String>(std::move(value), has_escape_chars);
return web::json::value(std::move(ptr)
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
value::String
#endif
);
}
#ifdef _WIN32
web::json::value web::json::value::string(const std::string& value)
{
std::unique_ptr<details::_Value> ptr =
utility::details::make_unique<details::_String>(utility::conversions::to_utf16string(value));
return web::json::value(std::move(ptr)
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
value::String
#endif
);
}
#endif
web::json::value web::json::value::object(bool keep_order)
{
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Object>(keep_order);
return web::json::value(std::move(ptr)
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
value::Object
#endif
);
}
web::json::value web::json::value::object(std::vector<std::pair<::utility::string_t, value>> fields, bool keep_order)
{
std::unique_ptr<details::_Value> ptr =
utility::details::make_unique<details::_Object>(std::move(fields), keep_order);
return web::json::value(std::move(ptr)
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
value::Object
#endif
);
}
web::json::value web::json::value::array()
{
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>();
return web::json::value(std::move(ptr)
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
value::Array
#endif
);
}
web::json::value web::json::value::array(size_t size)
{
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>(size);
return web::json::value(std::move(ptr)
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
value::Array
#endif
);
}
web::json::value web::json::value::array(std::vector<value> elements)
{
std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>(std::move(elements));
return web::json::value(std::move(ptr)
#ifdef ENABLE_JSON_VALUE_VISUALIZER
,
value::Array
#endif
);
}
const web::json::number& web::json::value::as_number() const { return m_value->as_number(); }
double web::json::value::as_double() const { return m_value->as_double(); }
int web::json::value::as_integer() const { return m_value->as_integer(); }
bool web::json::value::as_bool() const { return m_value->as_bool(); }
json::array& web::json::value::as_array() { return m_value->as_array(); }
const json::array& web::json::value::as_array() const { return m_value->as_array(); }
json::object& web::json::value::as_object() { return m_value->as_object(); }
const json::object& web::json::value::as_object() const { return m_value->as_object(); }
bool web::json::number::is_int32() const
{
switch (m_type)
{
case signed_type:
return m_intval >= (std::numeric_limits<int32_t>::min)() && m_intval <= (std::numeric_limits<int32_t>::max)();
case unsigned_type: return m_uintval <= (std::numeric_limits<int32_t>::max)();
case double_type:
default: return false;
}
}
bool web::json::number::is_uint32() const
{
switch (m_type)
{
case signed_type: return m_intval >= 0 && m_intval <= (std::numeric_limits<uint32_t>::max)();
case unsigned_type: return m_uintval <= (std::numeric_limits<uint32_t>::max)();
case double_type:
default: return false;
}
}
bool web::json::number::is_int64() const
{
switch (m_type)
{
case signed_type: return true;
case unsigned_type: return m_uintval <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)());
case double_type:
default: return false;
}
}
bool web::json::details::_String::has_escape_chars(const _String& str)
{
return std::any_of(std::begin(str.m_string), std::end(str.m_string), [](utility::string_t::value_type const x) {
if (x <= 31)
{
return true;
}
if (x == '"')
{
return true;
}
if (x == '\\')
{
return true;
}
return false;
});
}
web::json::value::value_type json::value::type() const { return m_value->type(); }
bool json::value::is_integer() const
{
if (!is_number())
{
return false;
}
return m_value->is_integer();
}
bool json::value::is_double() const
{
if (!is_number())
{
return false;
}
return m_value->is_double();
}
json::value& web::json::details::_Object::index(const utility::string_t& key) { return m_object[key]; }
bool web::json::details::_Object::has_field(const utility::string_t& key) const
{
return m_object.find(key) != m_object.end();
}
bool web::json::value::has_number_field(const utility::string_t& key) const
{
return has_field(key) && at(key).is_number();
}
bool web::json::value::has_integer_field(const utility::string_t& key) const
{
return has_field(key) && at(key).is_integer();
}
bool web::json::value::has_double_field(const utility::string_t& key) const
{
return has_field(key) && at(key).is_double();
}
bool web::json::value::has_boolean_field(const utility::string_t& key) const
{
return has_field(key) && at(key).is_boolean();
}
bool web::json::value::has_string_field(const utility::string_t& key) const
{
return has_field(key) && at(key).is_string();
}
bool web::json::value::has_array_field(const utility::string_t& key) const
{
return has_field(key) && at(key).is_array();
}
bool web::json::value::has_object_field(const utility::string_t& key) const
{
return has_field(key) && at(key).is_object();
}
utility::string_t json::value::to_string() const
{
#ifndef _WIN32
utility::details::scoped_c_thread_locale locale;
#endif
return m_value->to_string();
}
bool json::value::operator==(const json::value& other) const
{
if (this->m_value.get() == other.m_value.get()) return true;
if (this->type() != other.type()) return false;
switch (this->type())
{
case Null: return true;
case Number: return this->as_number() == other.as_number();
case Boolean: return this->as_bool() == other.as_bool();
case String: return this->as_string() == other.as_string();
case Object:
return static_cast<const json::details::_Object*>(this->m_value.get())
->is_equal(static_cast<const json::details::_Object*>(other.m_value.get()));
case Array:
return static_cast<const json::details::_Array*>(this->m_value.get())
->is_equal(static_cast<const json::details::_Array*>(other.m_value.get()));
}
__assume(0);
}
void web::json::value::erase(size_t index) { return this->as_array().erase(index); }
void web::json::value::erase(const utility::string_t& key) { return this->as_object().erase(key); }
// at() overloads
web::json::value& web::json::value::at(size_t index) { return this->as_array().at(index); }
const web::json::value& web::json::value::at(size_t index) const { return this->as_array().at(index); }
web::json::value& web::json::value::at(const utility::string_t& key) { return this->as_object().at(key); }
const web::json::value& web::json::value::at(const utility::string_t& key) const { return this->as_object().at(key); }
web::json::value& web::json::value::operator[](const utility::string_t& key)
{
if (this->is_null())
{
m_value.reset(new web::json::details::_Object(details::g_keep_json_object_unsorted));
#ifdef ENABLE_JSON_VALUE_VISUALIZER
m_kind = value::Object;
#endif
}
return m_value->index(key);
}
web::json::value& web::json::value::operator[](size_t index)
{
if (this->is_null())
{
m_value.reset(new web::json::details::_Array());
#ifdef ENABLE_JSON_VALUE_VISUALIZER
m_kind = value::Array;
#endif
}
return m_value->index(index);
}
// Remove once VS 2013 is no longer supported.
#if defined(_WIN32) && _MSC_VER < 1900
static web::json::details::json_error_category_impl instance;
#endif
const web::json::details::json_error_category_impl& web::json::details::json_error_category()
{
#if !defined(_WIN32) || _MSC_VER >= 1900
static web::json::details::json_error_category_impl instance;
#endif
return instance;
}

1279
deps/cpprestsdk/src/json/json_parsing.cpp vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,254 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* HTTP Library: JSON parser and writer
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include "pch.h"
#include <stdio.h>
#ifndef _WIN32
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif
using namespace web;
using namespace web::json;
using namespace utility;
using namespace utility::conversions;
//
// JSON Serialization
//
#ifdef _WIN32
void web::json::value::serialize(std::ostream& stream) const
{
// This has better performance than writing directly to stream.
std::string str;
m_value->serialize_impl(str);
stream << str;
}
void web::json::value::format(std::basic_string<wchar_t>& string) const { m_value->format(string); }
#endif
void web::json::value::serialize(utility::ostream_t& stream) const
{
#ifndef _WIN32
utility::details::scoped_c_thread_locale locale;
#endif
// This has better performance than writing directly to stream.
utility::string_t str;
m_value->serialize_impl(str);
stream << str;
}
void web::json::value::format(std::basic_string<char>& string) const { m_value->format(string); }
template<typename CharType>
void web::json::details::append_escape_string(std::basic_string<CharType>& str,
const std::basic_string<CharType>& escaped)
{
for (const auto& ch : escaped)
{
switch (ch)
{
case '\"':
str += '\\';
str += '\"';
break;
case '\\':
str += '\\';
str += '\\';
break;
case '\b':
str += '\\';
str += 'b';
break;
case '\f':
str += '\\';
str += 'f';
break;
case '\r':
str += '\\';
str += 'r';
break;
case '\n':
str += '\\';
str += 'n';
break;
case '\t':
str += '\\';
str += 't';
break;
default:
// If a control character then must unicode escaped.
if (ch >= 0 && ch <= 0x1F)
{
static const std::array<CharType, 16> intToHex = {
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}};
str += '\\';
str += 'u';
str += '0';
str += '0';
str += intToHex[(ch & 0xF0) >> 4];
str += intToHex[ch & 0x0F];
}
else
{
str += ch;
}
}
}
}
void web::json::details::format_string(const utility::string_t& key, utility::string_t& str)
{
str.push_back('"');
append_escape_string(str, key);
str.push_back('"');
}
#ifdef _WIN32
void web::json::details::format_string(const utility::string_t& key, std::string& str)
{
str.push_back('"');
append_escape_string(str, utility::conversions::to_utf8string(key));
str.push_back('"');
}
#endif
void web::json::details::_String::format(std::basic_string<char>& str) const
{
str.push_back('"');
if (m_has_escape_char)
{
append_escape_string(str, utility::conversions::to_utf8string(m_string));
}
else
{
str.append(utility::conversions::to_utf8string(m_string));
}
str.push_back('"');
}
void web::json::details::_Number::format(std::basic_string<char>& stream) const
{
if (m_number.m_type != number::type::double_type)
{
// #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator.
const size_t tempSize = std::numeric_limits<uint64_t>::digits10 + 3;
char tempBuffer[tempSize];
#ifdef _WIN32
// This can be improved performance-wise if we implement our own routine
if (m_number.m_type == number::type::signed_type)
_i64toa_s(m_number.m_intval, tempBuffer, tempSize, 10);
else
_ui64toa_s(m_number.m_uintval, tempBuffer, tempSize, 10);
const auto numChars = strnlen_s(tempBuffer, tempSize);
#else
int numChars;
if (m_number.m_type == number::type::signed_type)
numChars = snprintf(tempBuffer, tempSize, "%" PRId64, m_number.m_intval);
else
numChars = snprintf(tempBuffer, tempSize, "%" PRIu64, m_number.m_uintval);
#endif
stream.append(tempBuffer, numChars);
}
else
{
// #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null
// terminator
const size_t tempSize = std::numeric_limits<double>::digits10 + 10;
char tempBuffer[tempSize];
#ifdef _WIN32
const auto numChars = _sprintf_s_l(tempBuffer,
tempSize,
"%.*g",
utility::details::scoped_c_thread_locale::c_locale(),
std::numeric_limits<double>::digits10 + 2,
m_number.m_value);
#else
const auto numChars =
snprintf(tempBuffer, tempSize, "%.*g", std::numeric_limits<double>::digits10 + 2, m_number.m_value);
#endif
stream.append(tempBuffer, numChars);
}
}
#ifdef _WIN32
void web::json::details::_String::format(std::basic_string<wchar_t>& str) const
{
str.push_back(L'"');
if (m_has_escape_char)
{
append_escape_string(str, m_string);
}
else
{
str.append(m_string);
}
str.push_back(L'"');
}
void web::json::details::_Number::format(std::basic_string<wchar_t>& stream) const
{
if (m_number.m_type != number::type::double_type)
{
// #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator.
const size_t tempSize = std::numeric_limits<uint64_t>::digits10 + 3;
wchar_t tempBuffer[tempSize];
if (m_number.m_type == number::type::signed_type)
_i64tow_s(m_number.m_intval, tempBuffer, tempSize, 10);
else
_ui64tow_s(m_number.m_uintval, tempBuffer, tempSize, 10);
stream.append(tempBuffer, wcsnlen_s(tempBuffer, tempSize));
}
else
{
// #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null
// terminator
const size_t tempSize = std::numeric_limits<double>::digits10 + 10;
wchar_t tempBuffer[tempSize];
const int numChars = _swprintf_s_l(tempBuffer,
tempSize,
L"%.*g",
utility::details::scoped_c_thread_locale::c_locale(),
std::numeric_limits<double>::digits10 + 2,
m_number.m_value);
stream.append(tempBuffer, numChars);
}
}
#endif
const utility::string_t& web::json::details::_String::as_string() const { return m_string; }
const utility::string_t& web::json::value::as_string() const { return m_value->as_string(); }
utility::string_t json::value::serialize() const
{
#ifndef _WIN32
utility::details::scoped_c_thread_locale locale;
#endif
return m_value->to_string();
}

File diff suppressed because it is too large Load diff

260
deps/cpprestsdk/src/utilities/base64.cpp vendored Normal file
View file

@ -0,0 +1,260 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include "pch.h"
using namespace web;
using namespace utility;
std::vector<unsigned char> _from_base64(const utility::string_t& str);
utility::string_t _to_base64(const unsigned char* ptr, size_t size);
std::vector<unsigned char> __cdecl conversions::from_base64(const utility::string_t& str) { return _from_base64(str); }
utility::string_t __cdecl conversions::to_base64(const std::vector<unsigned char>& input)
{
if (input.size() == 0)
{
// return empty string
return utility::string_t();
}
return _to_base64(&input[0], input.size());
}
utility::string_t __cdecl conversions::to_base64(uint64_t input)
{
return _to_base64(reinterpret_cast<const unsigned char*>(&input), sizeof(input));
}
static const char* _base64_enctbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const std::array<unsigned char, 128> _base64_dectbl = {
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62,
255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, 255, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255}};
struct _triple_byte
{
unsigned char _1_1 : 2;
unsigned char _0 : 6;
unsigned char _2_1 : 4;
unsigned char _1_2 : 4;
unsigned char _3 : 6;
unsigned char _2_2 : 2;
};
struct _double_byte
{
unsigned char _1_1 : 2;
unsigned char _0 : 6;
unsigned char _2_1 : 4;
unsigned char _1_2 : 4;
};
struct _single_byte
{
unsigned char _1_1 : 2;
unsigned char _0 : 6;
};
//
// A note on the implementation of BASE64 encoding and decoding:
//
// This is a fairly basic and naive implementation; there is probably a lot of room for
// performance improvement, as well as for adding options such as support for URI-safe base64,
// ignoring CRLF, relaxed validation rules, etc. The decoder is currently pretty strict.
//
#ifdef __GNUC__
// gcc is concerned about the bitfield uses in the code, something we simply need to ignore.
#pragma GCC diagnostic ignored "-Wconversion"
#endif
std::vector<unsigned char> _from_base64(const utility::string_t& input)
{
std::vector<unsigned char> result;
if (input.empty()) return result;
size_t padding = 0;
// Validation
{
auto size = input.size();
if ((size % 4) != 0)
{
throw std::runtime_error("length of base64 string is not an even multiple of 4");
}
for (auto iter = input.begin(); iter != input.end(); ++iter, --size)
{
const size_t ch_sz = static_cast<size_t>(*iter);
if (ch_sz >= _base64_dectbl.size() || _base64_dectbl[ch_sz] == 255)
{
throw std::runtime_error("invalid character found in base64 string");
}
if (_base64_dectbl[ch_sz] == 254)
{
padding++;
// padding only at the end
if (size > 2)
{
throw std::runtime_error("invalid padding character found in base64 string");
}
if (size == 2)
{
const size_t ch2_sz = static_cast<size_t>(*(iter + 1));
if (ch2_sz >= _base64_dectbl.size() || _base64_dectbl[ch2_sz] != 254)
{
throw std::runtime_error("invalid padding character found in base64 string");
}
}
}
}
}
auto size = input.size();
const char_t* ptr = &input[0];
auto outsz = (size / 4) * 3;
outsz -= padding;
result.resize(outsz);
size_t idx = 0;
for (; size > 4; ++idx)
{
unsigned char target[3];
memset(target, 0, sizeof(target));
_triple_byte* record = reinterpret_cast<_triple_byte*>(target);
unsigned char val0 = _base64_dectbl[ptr[0]];
unsigned char val1 = _base64_dectbl[ptr[1]];
unsigned char val2 = _base64_dectbl[ptr[2]];
unsigned char val3 = _base64_dectbl[ptr[3]];
record->_0 = val0;
record->_1_1 = val1 >> 4;
result[idx] = target[0];
record->_1_2 = val1 & 0xF;
record->_2_1 = val2 >> 2;
result[++idx] = target[1];
record->_2_2 = val2 & 0x3;
record->_3 = val3 & 0x3F;
result[++idx] = target[2];
ptr += 4;
size -= 4;
}
// Handle the last four bytes separately, to avoid having the conditional statements
// in all the iterations (a performance issue).
{
unsigned char target[3];
memset(target, 0, sizeof(target));
_triple_byte* record = reinterpret_cast<_triple_byte*>(target);
unsigned char val0 = _base64_dectbl[ptr[0]];
unsigned char val1 = _base64_dectbl[ptr[1]];
unsigned char val2 = _base64_dectbl[ptr[2]];
unsigned char val3 = _base64_dectbl[ptr[3]];
record->_0 = val0;
record->_1_1 = val1 >> 4;
result[idx] = target[0];
record->_1_2 = val1 & 0xF;
if (val2 != 254)
{
record->_2_1 = val2 >> 2;
result[++idx] = target[1];
}
else
{
// There shouldn't be any information (ones) in the unused bits,
if (record->_1_2 != 0)
{
throw std::runtime_error("Invalid end of base64 string");
}
return result;
}
record->_2_2 = val2 & 0x3;
if (val3 != 254)
{
record->_3 = val3 & 0x3F;
result[++idx] = target[2];
}
else
{
// There shouldn't be any information (ones) in the unused bits.
if (record->_2_2 != 0)
{
throw std::runtime_error("Invalid end of base64 string");
}
return result;
}
}
return result;
}
utility::string_t _to_base64(const unsigned char* ptr, size_t size)
{
utility::string_t result;
for (; size >= 3;)
{
const _triple_byte* record = reinterpret_cast<const _triple_byte*>(ptr);
unsigned char idx0 = record->_0;
unsigned char idx1 = (record->_1_1 << 4) | record->_1_2;
unsigned char idx2 = (record->_2_1 << 2) | record->_2_2;
unsigned char idx3 = record->_3;
result.push_back(char_t(_base64_enctbl[idx0]));
result.push_back(char_t(_base64_enctbl[idx1]));
result.push_back(char_t(_base64_enctbl[idx2]));
result.push_back(char_t(_base64_enctbl[idx3]));
size -= 3;
ptr += 3;
}
switch (size)
{
case 1:
{
const _single_byte* record = reinterpret_cast<const _single_byte*>(ptr);
unsigned char idx0 = record->_0;
unsigned char idx1 = (record->_1_1 << 4);
result.push_back(char_t(_base64_enctbl[idx0]));
result.push_back(char_t(_base64_enctbl[idx1]));
result.push_back('=');
result.push_back('=');
break;
}
case 2:
{
const _double_byte* record = reinterpret_cast<const _double_byte*>(ptr);
unsigned char idx0 = record->_0;
unsigned char idx1 = (record->_1_1 << 4) | record->_1_2;
unsigned char idx2 = (record->_2_1 << 2);
result.push_back(char_t(_base64_enctbl[idx0]));
result.push_back(char_t(_base64_enctbl[idx1]));
result.push_back(char_t(_base64_enctbl[idx2]));
result.push_back('=');
break;
}
}
return result;
}

View file

@ -0,0 +1,157 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Credential and proxy utilities.
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#include "pch.h"
#include <assert.h>
#if defined(_WIN32) && !defined(__cplusplus_winrt)
#include <Wincrypt.h>
#endif
#if defined(__cplusplus_winrt)
#include <robuffer.h>
#endif
namespace web
{
namespace details
{
#if defined(_WIN32) && !defined(CPPREST_TARGET_XP)
#if defined(__cplusplus_winrt)
// Helper function to zero out memory of an IBuffer.
void winrt_secure_zero_buffer(Windows::Storage::Streams::IBuffer ^ buffer)
{
Microsoft::WRL::ComPtr<IInspectable> bufferInspectable(reinterpret_cast<IInspectable*>(buffer));
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
bufferInspectable.As(&bufferByteAccess);
// This shouldn't happen but if can't get access to the raw bytes for some reason
// then we can't zero out.
byte* rawBytes;
if (bufferByteAccess->Buffer(&rawBytes) == S_OK)
{
SecureZeroMemory(rawBytes, buffer->Length);
}
}
winrt_encryption::winrt_encryption(const std::wstring& data)
{
auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider(
ref new Platform::String(L"Local=user"));
// Create buffer containing plain text password.
Platform::ArrayReference<unsigned char> arrayref(
reinterpret_cast<unsigned char*>(const_cast<std::wstring::value_type*>(data.c_str())),
static_cast<unsigned int>(data.size()) * sizeof(std::wstring::value_type));
Windows::Storage::Streams::IBuffer ^ plaintext =
Windows::Security::Cryptography::CryptographicBuffer::CreateFromByteArray(arrayref);
m_buffer = pplx::create_task(provider->ProtectAsync(plaintext));
m_buffer.then(
[plaintext](pplx::task<Windows::Storage::Streams::IBuffer ^>) { winrt_secure_zero_buffer(plaintext); });
}
plaintext_string winrt_encryption::decrypt() const
{
// To fully guarantee asynchrony would require significant impact on existing code. This code path
// is never run on a user's thread and is only done once when setting up a connection.
auto encrypted = m_buffer.get();
auto provider = ref new Windows::Security::Cryptography::DataProtection::DataProtectionProvider();
auto plaintext = pplx::create_task(provider->UnprotectAsync(encrypted)).get();
// Get access to raw bytes in plain text buffer.
Microsoft::WRL::ComPtr<IInspectable> bufferInspectable(reinterpret_cast<IInspectable*>(plaintext));
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
bufferInspectable.As(&bufferByteAccess);
byte* rawPlaintext;
const auto& result = bufferByteAccess->Buffer(&rawPlaintext);
if (result != S_OK)
{
throw ::utility::details::create_system_error(result);
}
// Construct string and zero out memory from plain text buffer.
auto data = plaintext_string(
new std::wstring(reinterpret_cast<const std::wstring::value_type*>(rawPlaintext), plaintext->Length / 2));
SecureZeroMemory(rawPlaintext, plaintext->Length);
return std::move(data);
}
#else
win32_encryption::win32_encryption(const std::wstring& data) : m_numCharacters(data.size())
{
// Early return because CryptProtectMemory crashes with empty string
if (m_numCharacters == 0)
{
return;
}
if (data.size() > (std::numeric_limits<DWORD>::max)() / sizeof(wchar_t))
{
throw std::length_error("Encryption string too long");
}
const auto dataSizeDword = static_cast<DWORD>(data.size() * sizeof(wchar_t));
// Round up dataSizeDword to be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
static_assert(CRYPTPROTECTMEMORY_BLOCK_SIZE == 16, "Power of 2 assumptions in this bit masking violated");
const auto mask = static_cast<DWORD>(CRYPTPROTECTMEMORY_BLOCK_SIZE - 1u);
const auto dataNumBytes = (dataSizeDword & ~mask) + ((dataSizeDword & mask) != 0) * CRYPTPROTECTMEMORY_BLOCK_SIZE;
assert((dataNumBytes % CRYPTPROTECTMEMORY_BLOCK_SIZE) == 0);
assert(dataNumBytes >= dataSizeDword);
m_buffer.resize(dataNumBytes);
memcpy_s(m_buffer.data(), m_buffer.size(), data.c_str(), dataNumBytes);
if (!CryptProtectMemory(m_buffer.data(), dataNumBytes, CRYPTPROTECTMEMORY_SAME_PROCESS))
{
throw ::utility::details::create_system_error(GetLastError());
}
}
win32_encryption::~win32_encryption() { SecureZeroMemory(m_buffer.data(), m_buffer.size()); }
plaintext_string win32_encryption::decrypt() const
{
// Copy the buffer and decrypt to avoid having to re-encrypt.
auto result = plaintext_string(new std::wstring(reinterpret_cast<const std::wstring::value_type*>(m_buffer.data()),
m_buffer.size() / sizeof(wchar_t)));
auto& data = *result;
if (!m_buffer.empty())
{
if (!CryptUnprotectMemory(&data[0], static_cast<DWORD>(m_buffer.size()), CRYPTPROTECTMEMORY_SAME_PROCESS))
{
throw ::utility::details::create_system_error(GetLastError());
}
assert(m_numCharacters <= m_buffer.size());
SecureZeroMemory(&data[m_numCharacters], data.size() - m_numCharacters);
data.erase(m_numCharacters);
}
return result;
}
#endif
#endif
void zero_memory_deleter::operator()(::utility::string_t* data) const
{
CASABLANCA_UNREFERENCED_PARAMETER(data);
#if defined(_WIN32)
SecureZeroMemory(&(*data)[0], data->size() * sizeof(::utility::string_t::value_type));
delete data;
#endif
}
} // namespace details
} // namespace web

View file

@ -0,0 +1,29 @@
# Code Organization
## Rules
- **Follow the pattern of what you already see in the code**
- Try to package new ideas/components into libraries that have nicely defined interfaces
- Package new ideas into classes or refactor existing ideas into a class as you extend
## Code Overview
General project organization:
#### The [`build`](/build) folder
Contains the Azure pipeline CI build scripts.
#### The [`deps`](/deps) folder
Contains other projects, that PowerToys uses as dependency.
#### The [`doc`](/doc) folder
Documentation for the project, including a [coding guide](/doc/coding) and [design docs](/doc/specs).
#### The [`installer`](/installer) folder
Contains the source code of the PowerToys installer.
#### The [`src`](/src) folder
Contains the source code of the PowerToys runner and of all of the PowerToys modules. **This is where the most of the magic happens.**
#### The [`tools`](/tools) folder
Various tools used by PowerToys. Includes the Visual Studio 2019 project template for new PowerToys.

5
doc/coding/style.md Normal file
View file

@ -0,0 +1,5 @@
# Coding Style
## Philosophy
1. If it's inserting something into the existing classes/functions, try to follow the existing style as closely as possible.
1. If it's brand new code or refactoring a complete class or area of the code, please follow as Modern C++ of a style as you can and reference the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines) as much as you possibly can.

BIN
doc/images/FZTutorial.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

BIN
doc/images/Logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
doc/images/MTNDWidget.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

BIN
doc/images/runner/tray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View file

@ -0,0 +1,27 @@
# Backlog
This file captures the prioritized list of issues the FancyZones team will tackle
## On deck
Implement multi-mon editor support [331](https://github.com/JaneaSystems/powertoys/issues/331)
Add telemetry to new editor [332](https://github.com/JaneaSystems/powertoys/issues/332)
## Backlog
Add tests to the new editor [333](https://github.com/JaneaSystems/powertoys/issues/333)
Hitting Esc while dragging should cancel the drag and not move the window into a zone [140](https://github.com/JaneaSystems/powertoys/issues/140)
Flash Zones is wayyyy too slow with multiple large monitors [137](https://github.com/JaneaSystems/powertoys/issues/137)
Cycle through windows in a Zone [145](https://github.com/JaneaSystems/powertoys/issues/145)
Minimize/restore windows in a zone as a group [144](https://github.com/JaneaSystems/powertoys/issues/144)
FancyZones should support custom layouts for different "environments" [149](https://github.com/JaneaSystems/powertoys/issues/149)
Win+arrow works between monitors [130](https://github.com/JaneaSystems/powertoys/issues/130)
Win+arrow is directional based on zone rect [131](https://github.com/JaneaSystems/powertoys/issues/131)
Dragging a zoned window should restore size to a checkpointed size instead of current rect [136](https://github.com/JaneaSystems/powertoys/issues/136)
FancyZones should merge with MTND and include zone moves in the pop-up [150](https://github.com/JaneaSystems/powertoys/issues/150)
Drag to edge of screen automatically switches virtual desktops [150](https://github.com/JaneaSystems/powertoys/issues/138)
Different color schemes [134](https://github.com/JaneaSystems/powertoys/issues/134)
Ensure you can easily see zone while dragging [131](https://github.com/JaneaSystems/powertoys/issues/131)
Visual updates for Win+Arrow [141](https://github.com/JaneaSystems/powertoys/issues/141)
Add a CLI for FancyZones [152](https://github.com/JaneaSystems/powertoys/issues/152)
Add "magnetic dragging and resizing" mode to FancyZones [153](https://github.com/JaneaSystems/powertoys/issues/153)
Create layout from current windows [127](https://github.com/JaneaSystems/powertoys/issues/127)
Zone sets that have a dynamic number of zones [128](https://github.com/JaneaSystems/powertoys/issues/128)

View file

@ -0,0 +1,25 @@
# PowerToys Backlog
The list below is the set of utilities we're considering and the rough priority order of the utilities. If you have feedback on the order of the utilities, please use the issues for each one to provide that feedback. Note that new features for existing utilities (dock / undock zone layouts for FancyZones) are tracked in teh abcklog for each utility.
## On deck
* Maximize to new desktop widget - The MTND widget shows a pop-up button when a user hovers over the maximize / restore button on any window. Clicking it creates a new desktop, sends the app to that desktop and maximizes the app on the new desktop.
* [Process terminate tool](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/Terminate%20Spec.md)
* [Batch file renamer](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/File%20Classification%20Spec.md)
* [Animated gif screen recorder](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/GIF%20Maker%20Spec.md)
## Backlog
HPlease use issues and votes to guide the project to suggest new ideas and help us prioritize the list below.
1. [Keyboard shortcut manager](https://github.com/microsoft/PowerToys/issues/6)
2. [Win+R replacement](https://github.com/microsoft/PowerToys/issues/44)
3. Resrouce use tool (maps between a resource like a file handle to an app and vice-versa)
4. Performance analysis over time to track which processes have been slowing down your machine
5. Better Alt+Tab including browser tab integration and search for running apps
6. [Battery tracker](https://github.com/microsoft/PowerToys/issues/7)
7. [Quick resolution swaps in taskbar](https://github.com/microsoft/PowerToys/issues/27)
8. Mouse events without focus
9. Cmd (or PS or Bash) from here
10. Contents menu file browsing

View file

@ -0,0 +1,13 @@
# Backlog
This file captures the prioritized list of issues for the Windows key shortcut guide
## On deck
Windows key shortcut guide animation performance is choppy [335](https://github.com/JaneaSystems/powertoys/issues/335)
Shortcut guide strings should be localized [336](https://github.com/JaneaSystems/powertoys/issues/336)
## Backlog
Add Win+Shift+S to the WKSG (screenshot tool) [151](https://github.com/JaneaSystems/powertoys/issues/151)
Replace SVG with software-generated content. [90](https://github.com/JaneaSystems/powertoys/issues/90)
Shortcut sorting [21](https://github.com/JaneaSystems/powertoys/issues/21)
Make shortcut descriptors clickable [6](https://github.com/JaneaSystems/powertoys/issues/6)

View file

@ -0,0 +1,215 @@
# FancyZones
## FancyZones
FancyZones is the base class that runs the show. It uses hooks to monitor for windows entering and exiting the move/size loop and to listen for key presses for hotkey interception. For every connected display, it creates a ZoneWindow which is used to display the active ZoneSet per monitor for use when editing the layout or displaying the drop targets. A ZoneSet is composed of one or more Zones which are the locations where windows can be easily positioned.
### SetWinEventHook
The main driving force behind FancyZones is the accessibility hook used to know when a window enters the move/size loop. It listens for EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, and EVENT_OBJECT_LOCATIONCHANGE. For each of these three events, it forwards on to the ZoneWindow associated with the monitor that the window being dragged is currently on.
### Keyboard Hook
A low-level keyboard hook is installed in order to, optionally, intercept Window+Arrow hotkeys. Traditionally, Win+Left/Right arrow will move a window between Windows Snap regions. This hook allows FancyZones to use Win+Left/Right arrow to move windows between Zones.
The hook also allows using 0-9 to change the active ZoneSet during a drag operation.
### Display Changes
During initial standup, FancyZones creates a ZoneWindow for each connected monitor. When it receives a WM_DISPLAYCHANGE, it updates the available ZoneWindows to reflect the state of the system (eg add a new ZoneWindow for newly connected monitor, delete ZoneWindow for disconnected monitor, etc)
### Interface
```
interface IFancyZones : public IUnknown
{
// Returns the main application window
IFACEMETHOD_(HWND, GetWindow)() = 0;
// Returns the global HINSTANCE for the process
IFACEMETHOD_(HINSTANCE, GetHInstance)() = 0;
// Returns the global Settings object used to look up individual settings throughout the product
IFACEMETHOD_(Settings, GetSettings)() = 0;
// Used in WinMain to initialize FancyZones and enter the message loop
IFACEMETHOD_(void, Run)() = 0;
// Toggles the visibility of all ZoneWindows
IFACEMETHOD_(void, ToggleZoneViewers)() = 0;
// Shows a single ZoneWindow in editor mode on the provided monitor
IFACEMETHOD_(void, ShowZoneEditorForMonitor)(_In_ HMONITOR monitor) = 0;
// Returns true if we are currently detecting a movesize loop
IFACEMETHOD_(bool, InMoveSize)() = 0;
// Called by the event hook in response to EVENT_SYSTEM_MOVESIZESTART
IFACEMETHOD(MoveSizeEnter)(_In_ HWND window, _In_ HMONITOR monitor, POINT ptScreen) = 0;
// Called by the event hook in response to EVENT_SYSTEM_MOVESIZEEND
IFACEMETHOD(MoveSizeExit)(_In_ HWND window, POINT ptScreen) = 0;
// Called by the event hook in response to EVENT_OBJECT_LOCATIONCHANGE
IFACEMETHOD(MoveSizeUpdate)(_In_ HMONITOR monitor, POINT ptScreen) = 0;
// Called during startup or on WM_DISPLAYCHANGE to add a ZoneWindow to the collection
// There will be one ZoneWindow per connected monitor
IFACEMETHOD(AddZoneWindow)(_In_ IZoneWindow* zoneWindow, _In_ HMONITOR monitor) = 0;
// Called in response to WM_DISPLAYCHANGE from the main application window
IFACEMETHOD_(void, OnDisplayChange)(DisplayChangeType changeType) = 0;
// Used to move the specified HWND into Zone
// The ZoneSet used is found by looking up the monitor that window is currently on
// This gets called to keep windows in their current zones after a WM_DISPLAYCHANGE
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(_In_ HWND window, int index) = 0;
// Used to filter out windows that the hook should not be processing
// Currently checks if the window's GWL_STYLE has WS_MAXIMIZEBOX
IFACEMETHOD_(bool, IsInterestingWindow)(_In_ HWND window) = 0;
// Called byt the event hook in response to EVENT_OBJECT_NAMECHANGE on the Desktop window
// The accessible name of the desktop window changes when the current virtual desktop changes
IFACEMETHOD_(void, VirtualDesktopChanged)() = 0;
// Returns the GUID of the current active virtual desktop
IFACEMETHOD_(GUID, GetCurrentVirtualDesktopId)() = 0;
// Called by the LL keyboard hook
// Used to override snap hotkeys and to change the active ZoneSet during a drag
IFACEMETHOD_(bool, OnKeyDown)(LPARAM lparam) = 0;
// Keep windows positioned inside their zones when the active ZoneSet changes
IFACEMETHOD_(void, MoveWindowsOnActiveZoneSetChange)() = 0;
};
```
## ZoneWindow
ZoneWindow is used to display the Zones a user can drop a window in during a drag operation, flash the Zones when the ZoneSet changes, and draw the Zone Editor UI when in edit mode. Basically, when a ZoneSet needs to be visualized, ZoneWindow does it.
### Interface
```
interface IZoneWindow : public IUnknown
{
// Shows the ZoneWindow
// If activate is true, set foreground to the window otherwise just show
IFACEMETHOD(ShowZoneWindow)(bool activate) = 0;
// Hide the ZoneWindow
IFACEMETHOD(HideZoneWindow)() = 0;
// Called when the drag enters the monitor this ZoneWindow is assigned to
IFACEMETHOD(MoveSizeEnter)(_In_ HWND window, POINT ptScreen, DragMode dragMode) = 0;
// Called when the drag exits the monitor
IFACEMETHOD(MoveSizeExit)(_In_ HWND window, POINT ptScreen) = 0;
// Called when the drag updates position on this monitor
IFACEMETHOD(MoveSizeUpdate)(POINT ptScreen, DragMode dragMode) = 0;
// Called when a drag ends and the window is not dropped in a Zone
IFACEMETHOD(MoveSizeCancel)() = 0;
// Returns the DragMode of the current drag operation
// DragMode allows for overriding drag behavior via settings or via hotkey
IFACEMETHOD_(DragMode, GetDragMode)() = 0;
// Part of the chain to move a window into a specific Zone
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(_In_ HWND window, int index) = 0;
// Used to cycle a window between zones via the hijacked snap hotkeys
IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(_In_ HWND window, DWORD vkCode) = 0;
// Called in response to WM_DISPLAYCHANGE
// Allows cleanup, if necessary, since ZoneWindow will be destroyed shortly thereafter
IFACEMETHOD_(void, OnDisplayChange)(DisplayChangeType type) = 0;
// Allows changing the active ZoneSet via key press either during a drag or while the ZoneWindow is in foreground
IFACEMETHOD_(void, CycleActiveZoneSet)(DWORD vkCode) = 0;
};
```
## ZoneSet
Collection of one or more Zones. Only one ZoneSet is active at a time per monitor.
### Interface
```
interface IZoneSet : public IUnknown
{
// Gets the unique ID used to identify this ZoneSet
IFACEMETHOD_(GUID, GetId)() = 0;
// Adds a Zone to the collection
IFACEMETHOD(AddZone)(_In_ Microsoft::WRL::ComPtr<IZone> zone, bool front) = 0;
// Removes a Zone from the collection
IFACEMETHOD(RemoveZone)(_In_ Microsoft::WRL::ComPtr<IZone> zone) = 0;
// Returns the topmost Zone at the given point
IFACEMETHOD_(Microsoft::WRL::ComPtr<IZone>, ZoneFromPoint)(POINT pt) = 0;
// Returns a Zone that the window is in
// Will return nullptr if the window is not in a Zone
IFACEMETHOD_(Microsoft::WRL::ComPtr<IZone>, ZoneFromWindow)(_In_ HWND window) = 0;
// Gets all the Zones
IFACEMETHOD_(std::vector<Microsoft::WRL::ComPtr<IZone>>, GetZones)() = 0;
// ZoneSetLayout
// * Grid - Pregenerated layout (2x2, 3x3, etc)
// * Row - Pregenerated layout in a single row
// * Focus - Pregenerated layout with a central focus Zone and fanned peripheral Zones
// * Custom - User generated Zone
IFACEMETHOD_(ZoneSetLayout, GetLayout)() = 0;
// The amount of default padding between Zones in a generated layout
IFACEMETHOD_(int, GetInnerPadding)() = 0;
// Makes a copy of the IZoneSet and marks it as ZoneSetLayout::Custom
IFACEMETHOD_(Microsoft::WRL::ComPtr<IZoneSet>, MakeCustomClone)() = 0;
// Persists ZoneSet data to the registry
IFACEMETHOD_(void, Save)() = 0;
// Moves a Zone to the front of the collection
IFACEMETHOD_(void, MoveZoneToFront)(_In_ Microsoft::WRL::ComPtr<IZone> zone) = 0;
// Moves a Zone to the back of the collection
IFACEMETHOD_(void, MoveZoneToBack)(_In_ Microsoft::WRL::ComPtr<IZone> zone) = 0;
// Part of the chain to move a window into a specific Zone
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(_In_ HWND window, _In_ HWND zoneWindow, int index) = 0;
// Part of the chain to move a window into a specific Zone
IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(_In_ HWND window, _In_ HWND zoneWindow, DWORD vkCode) = 0;
// Called when a drag ends or leaves the monitor this ZoneWindow is on
// This will remove the window from its currently assigned Zone and assign it
// to a different Zone based on the current cursor position
IFACEMETHOD_(void, MoveSizeExit)(_In_ HWND window, _In_ HWND zoneWindow, _In_ POINT ptClient) = 0;
};
```
## Zone
Basically a RECT and a map of HWND->RECT to keep track of where windows can be placed and which windows are currently in the Zone.
### Interface
```
interface IZone : public IUnknown
{
// Returns the RECT that this Zone represents
IFACEMETHOD_(RECT, GetZoneRect)() = 0;
// Returns true if the specified window is in this Zone's collection
IFACEMETHOD_(bool, ContainsWindow)(_In_ HWND window) = 0;
// Adds the window the collection
IFACEMETHOD_(void, AddWindowToZone)(_In_ HWND window, _In_ HWND zoneWindow, bool stampZone) = 0;
// Removes the window from the collection
IFACEMETHOD_(void, RemoveWindowFromZone)(_In_ HWND window, bool restoreSize) = 0;
// Sets an id for this Zone
// The id will be unique per ZoneSet
IFACEMETHOD_(void, SetId)(size_t id) = 0;
// Returns the id given to this Zone
IFACEMETHOD_(size_t, GetId)() = 0;
};
```

View file

@ -0,0 +1,57 @@
# Power Toys Settings Framework and Core Infrastructure
The Power Toys app will have a settings framework that each Power Toy can plug into. The settings framework has a UI frame that creates a page for each Power Toy. The UI frame should use the Navigation View “hamburger” UI. Each Power Toy will represent its settings as a json blob as described below.
Each Power Toy will line in a separate .dll and be run in a separate thread by the main Power Toys process. The main Power Toys .exe will expose key global Windows event handlers so that there is only one system-level hook for these critical events. The current set of Power Toys require these global events. This list will be amended as new Power Toys are authored that require additional global hooks.
* SetWinEventHook - FancyZones requires knowledge of when a window enters the move/size loop. It listens for EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, and EVENT_OBJECT_LOCATIONCHANGE messages from SetWinEventHook.
* Low-level keyboard hook - The Windows key Shortcut Guide and FancyZones both require low-level keybord hooks to intercept keyboard input and get a first chance to process it. Other Power Toys will require this as well
* Each Power Toy must listen for 4 events:
* Enable When invoked, enables the Power Toys functionality and performs any necessary initialization. Invoked with a JSON string from the persisted settings store
* Disable When invoked, disables the Power Toys functionality and performs any clean-up to suspend all resource use
* OutputSettings Return a json serialized blob of the settings for the Power Toy
* InputSettings Invoked with a JSON string with updated settings from the UI which is then deserialized and the state is applied. If the settings cannot be applied by the Power Toy, the PT must return an error and an error string for the end user
* Each Power Toy may optionally provide one or more custom configuration UIs that can be invoked from its settings page
* Each custom UI is specified as a JSON string in the settings property bag
* The Power Toy must provide a named method that returns a serialized JSON settings string for the settings framework to call
* The method should launch UI to edit the settings but the UI shown must be asynchronous and not block the setting UI
* The Power Toys main .exe will provide a method called InvokeSettingsUI that will show the settings dialog for the calling Power Toy.
* Settings will be serialized by the settings framework and will be read at launch of the Power Toys framework and each Power Toys settings will be passed into the PTs Enable method
* Settings will be serialized on a per-user basis
* The Settings JSON format will be versioned nad each payload must specify it's version attribute. The initial version is 1.0
## Power Toys Settings Object
The settings JSON object for each Power Toy should provide:
* Title string
* Icon
* Logo Image
* Credits string
* Credits link
* Settings property bag. Each item in the property bag has two items:
* String: display name
* String: property / editor type
* Version number: Currently only 1.0 is supported
Property Bag of settings in priority order (type->editor)
* Bool->slide switch
* Int->free text box
* String->free text box
* Int ->Up/Down spinner
* Color-> Color picker
* Image->File picker, preview area, drag and drop
* Cursor->file picker and drop down, possibly an image
* Property Bag JSON string->Button to launch a custom editor from the Power Toy
* Method name to invoke. The method will return a serialized JSON string with the updated custom editor settings
* String to display on the button
* Percentage->Slider
* Time->Time picker
* Date->Date picker
* IP address->masked text box
## PowerToys Main Settings Page
* Need to get Nick to help with the settings UI design (see attached for a whiteboard sketch)
* Need to have a settings page for overall PowerToys which will include the following
* Check for updates
* Startup at launch
* Enable / disable for each utility.
* This invokes the Enable and Disable events for the PowerToy and suspends all resource use including CPU, GPU, Networking, Disk I/O and memory commit
* The settings UI should have an “Apply” button which will push the settings object to

85
doc/specs/Shared-hooks.md Normal file
View file

@ -0,0 +1,85 @@
# Shared hooks
To minimize the performance impact on the machine only `runner` installs global hooks, passing the events to registered callbacks in each PowerToy module.
When a PowerToy module is loaded, the `runner` calls the [`get_events()`](/src/modules/interface/powertoy_module_interface.h#L40) method to get a NULL-terminated array of NULL-terminated strings with the names of the events that the PowerToy wants to subscribe to. A `const wchar_t*` string is provided for each of the event names.
Events are signalled by the `runner` calling the [`signal_event(name, data)`](/src/modules/interface/powertoy_module_interface.h#L53) method of the PowerToy module. The `name` parameter contains the NULL-terminated name of the event. The `data` parameter and the method return value are specific for each event.
Currently supported hooks:
* `"ll_keyboard"` - [Low Level Keyboard Hook](#low-level-keyboard-hook)
* `"win_hook_event"` - [Windows Event Hook](#windows-event-hook)
## Low Level Keyboard Hook
This event is signaled whenever the user presses or releases a key on the keyboard. To subscribe to this event, add `"ll_keyboard"` to the table returned by the `get_events()` method.
The PowerToys runner installs low-level keyboard hook using `SetWindowsHookEx(WH_KEYBOARD_LL, ...)`. See [this MSDN page](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v%3Dvs.85)) for details.
When a keyboard event is signaled and `ncCode` equals `HC_ACTION`, the `wParam` and `lParam` event parameters are passed to all subscribed clients in the [`LowlevelKeyboardEvent`](/src/modules/interface/lowlevel_keyboard_event_data.h#L38-L41) struct.
The `intptr_t data` event argument is a pointer to the `LowlevelKeyboardEvent` struct.
A non-zero return value from any of the subscribed PowerToys will cause the runner hook proc to return 1, thus swallowing the keyboard event.
Example usage, that makes Windows ignore the L key:
```c++
virtual const wchar_t** get_events() override {
static const wchar_t* events[2] = { ll_keyboard,
nullptr };
return events;
}
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override {
if (wcscmp(name, ll_keyboard) == 0) {
auto& event = *(reinterpret_cast<LowlevelKeyboardEvent*>(data));
// The L key has vkCode of 0x4C, see:
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
if (event.wParam == WM_KEYDOWN && event.lParam->vkCode == 0x4C) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
}
```
## Windows Event Hook
This event is signaled for [a range of events](https://docs.microsoft.com/pl-pl/windows/win32/winauto/event-constants). To subscribe to this event, add `"win_hook_event"` to the table returned by the `get_events()` method. See [this MSDN doc](https://docs.microsoft.com/pl-pl/windows/win32/api/winuser/nf-winuser-setwineventhook) for details.
The `intptr_t data` event argument is a pointer to the [`WinHookEvent`](/src/modules/interface/win_hook_event_data.h#L43-L50) struct.
The return value of the event handler is ignored.
Example usage, that detects a window being resized:
```c++
virtual const wchar_t** get_events() override {
static const wchar_t* events[2] = { win_hook_event,
nullptr };
return events;
}
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override {
if (wcscmp(name, win_hook_event) == 0) {
auto& event = *(reinterpret_cast<WinHookEvent*>(data));
switch (event.event) {
case EVENT_SYSTEM_MOVESIZESTART:
size_start(event.hwnd);
break;
case EVENT_SYSTEM_MOVESIZEEND:
size_end(event.hwnd);
break;
default:
break;
}
}
return 0;
}
```
Taking too long to process the events has negative impact on the whole system performance. To address this, the events are signaled from a different thread, not from the event hook callback itself.

View file

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29215.179
MinimumVisualStudioVersion = 10.0.40219.1
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "PowerToysSetup", "PowerToysSetup\PowerToysSetup.wixproj", "{022A9D30-7C4F-416D-A9DF-5FF2661CC0AD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToysSetupCustomActions", "PowerToysSetupCustomActions\PowerToysSetupCustomActions.vcxproj", "{32F3882B-F2D6-4586-B5ED-11E39E522BD3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{022A9D30-7C4F-416D-A9DF-5FF2661CC0AD}.Debug|x64.ActiveCfg = Debug|x64
{022A9D30-7C4F-416D-A9DF-5FF2661CC0AD}.Debug|x64.Build.0 = Debug|x64
{022A9D30-7C4F-416D-A9DF-5FF2661CC0AD}.Release|x64.ActiveCfg = Release|x64
{022A9D30-7C4F-416D-A9DF-5FF2661CC0AD}.Release|x64.Build.0 = Release|x64
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Debug|x64.ActiveCfg = Debug|x64
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Debug|x64.Build.0 = Debug|x64
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Release|x64.ActiveCfg = Release|x64
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B7A3DA30-D443-40FF-AC51-988AD41E3962}
EndGlobalSection
EndGlobal

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<UI>
<Dialog Id="PTInstallDirDlg" Width="370" Height="270" Title="!(loc.InstallDirDlg_Title)">
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" />
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" />
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
<Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.InstallDirDlgDescription)" />
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.InstallDirDlgTitle)" />
<Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" />
<Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
<Control Id="FolderLabel" Type="Text" X="20" Y="60" Width="290" Height="30" NoPrefix="yes" Text="!(loc.InstallDirDlgFolderLabel)" />
<Control Id="Folder" Type="PathEdit" X="20" Y="100" Width="320" Height="18" Property="WIXUI_INSTALLDIR" Indirect="yes" />
<Control Id="ChangeFolder" Type="PushButton" X="20" Y="120" Width="56" Height="17" Text="!(loc.InstallDirDlgChange)" />
<Control Id="StartMenuShortcutCheckBox" Type="CheckBox" X="20" Y="160" Width="290" Height="17" Property="INSTALLSTARTMENUSHORTCUT" CheckBoxValue="1" Text="Create a shortcut for [ProductName] in the start menu." />
<Control Id="DesktopShortcutCheckBox" Type="CheckBox" X="20" Y="180" Width="290" Height="17" Property="INSTALLDESKTOPSHORTCUT" CheckBoxValue="1" Text="Create a shortcut for [ProductName] in the desktop." />
<Control Id="ScheduledTaskCheckBox" Type="CheckBox" X="20" Y="200" Width="330" Height="17" Property="CREATESCHEDULEDTASK" CheckBoxValue="1" Text="Automatically start [ProductName] at logon." />
</Dialog>
</UI>
</Fragment>
</Wix>

View file

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
<!--
First-time install dialog sequence:
- WixUI_WelcomeDlg
- WixUI_LicenseAgreementDlg
- WixUI_PTInstallDirDlg
- WixUI_VerifyReadyDlg
- WixUI_DiskCostDlg
Maintenance dialog sequence:
- WixUI_MaintenanceWelcomeDlg
- WixUI_MaintenanceTypeDlg
- WixUI_PTInstallDirDlg
- WixUI_VerifyReadyDlg
Patch dialog sequence:
- WixUI_WelcomeDlg
- WixUI_VerifyReadyDlg
-->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<UI Id="WixUI_PTInstallDir">
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
<Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
<Property Id="WixUI_Mode" Value="InstallDir" />
<DialogRef Id="BrowseDlg" />
<DialogRef Id="DiskCostDlg" />
<DialogRef Id="ErrorDlg" />
<DialogRef Id="FatalError" />
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<DialogRef Id="PrepareDlg" />
<DialogRef Id="ProgressDlg" />
<DialogRef Id="ResumeDlg" />
<DialogRef Id="UserExit" />
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
<Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
<Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">NOT Installed</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
<Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
<Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="PTInstallDirDlg">LicenseAccepted = "1"</Publish>
<Publish Dialog="PTInstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish>
<Publish Dialog="PTInstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
<Publish Dialog="PTInstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
<Publish Dialog="PTInstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
<Publish Dialog="PTInstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
<Publish Dialog="PTInstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
<Publish Dialog="PTInstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="PTInstallDirDlg" Order="1">NOT Installed</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
<Property Id="ARPNOMODIFY" Value="1" />
</UI>
<UIRef Id="WixUI_Common" />
</Fragment>
</Wix>

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<ProductVersion>3.10</ProductVersion>
<ProjectGuid>022a9d30-7c4f-416d-a9df-5ff2661cc0ad</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>PowerToysSetup</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<DefineConstants>Debug</DefineConstants>
<OutputPath>$(Platform)\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<OutputPath>$(Platform)\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="CustomDialogs\PTInstallDirDlg.wxs" />
<Compile Include="CustomDialogs\WixUI_PTInstallDir.wxs" />
<Compile Include="Product.wxs" />
</ItemGroup>
<ItemGroup>
<WixExtension Include="WixUtilExtension">
<HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
<Name>WixUtilExtension</Name>
</WixExtension>
<WixExtension Include="WixUIExtension">
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
<Name>WixUIExtension</Name>
</WixExtension>
</ItemGroup>
<ItemGroup>
<Folder Include="CustomDialogs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PowerToysSetupCustomActions\PowerToysSetupCustomActions.vcxproj">
<Name>PowerToysSetupCustomActions</Name>
<Project>{32f3882b-f2d6-4586-b5ed-11e39e522bd3}</Project>
<Private>True</Private>
<DoNotHarvest>True</DoNotHarvest>
<RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
<RefTargetDir>INSTALLFOLDER</RefTargetDir>
</ProjectReference>
</ItemGroup>
<Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
<Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
</Target>
<!--
To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Wix.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
<Product Id="*"
Name="PowerToys"
Language="1033"
Version="0.11.0"
Manufacturer="Microsoft"
UpgradeCode="42B84BF7-5FBF-473B-9C8B-049DC16F7708">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated" Platform="x64" />
<MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Property Id="WINDOWSBUILDNUMBER" Secure="yes">
<RegistrySearch Id="BuildNumberSearch" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion" Name="CurrentBuildNumber" Type="raw" />
</Property>
<Condition Message="This application is only supported on Windows 10 version 1803 (build 17134) or higher.">
<![CDATA[(WINDOWSBUILDNUMBER >= 17134)]]>
</Condition>
<Icon Id="powertoys.ico" SourceFile="$(var.BinX64Dir)\svgs\icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="powertoys.ico" />
<Feature Id="ProductFeature" Title="PowerToys" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
<UI>
<UIRef Id="WixUI_PTInstallDir"/>
<Publish Dialog="ExitDialog"
Control="Finish"
Event="DoAction"
Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Property="_REMOVE_ALL" Value="Yes">1</Publish>
<Publish Dialog="UserExit" Control="Finish" Event="DoAction" Value="TelemetryLogInstallCancel">NOT Installed</Publish>
<Publish Dialog="FatalError" Control="Finish" Event="DoAction" Value="TelemetryLogInstallFail">NOT Installed</Publish>
<Publish Dialog="UserExit" Control="Finish" Event="DoAction" Value="TelemetryLogUninstallCancel">Installed AND _REMOVE_ALL="Yes"</Publish>
<Publish Dialog="FatalError" Control="Finish" Event="DoAction" Value="TelemetryLogUninstallFail">Installed AND _REMOVE_ALL="Yes"</Publish>
<Publish Dialog="UserExit" Control="Finish" Event="DoAction" Value="TelemetryLogRepairCancel">Installed AND NOT (_REMOVE_ALL="Yes")</Publish>
<Publish Dialog="FatalError" Control="Finish" Event="DoAction" Value="TelemetryLogRepairFail">Installed AND NOT (_REMOVE_ALL="Yes")</Publish>
</UI>
<WixVariable Id="WixUIBannerBmp" Value="$(var.ProjectDir)\Bitmaps\banner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="$(var.ProjectDir)\Bitmaps\dialog.bmp" />
<WixVariable Id="WixUILicenseRtf" Value="$(var.RepoDir)\License.rtf" />
<Property Id="INSTALLSTARTMENUSHORTCUT" Value="1"/>
<Property Id="CREATESCHEDULEDTASK" Value="1"/>
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1"/>
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch PowerToys" />
<Property Id="WixShellExecTarget" Value="[#PowerToys.exe]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<InstallExecuteSequence>
<Custom Action="SetRegisterPowerToysSchTaskParam" Before="RegisterPowerToysSchTask" />
<Custom Action="RegisterPowerToysSchTask" After="InstallFiles">
NOT Installed and CREATESCHEDULEDTASK = 1
</Custom>
<Custom Action="WixCloseApplications" Before="RemoveFiles" />
<Custom Action="RemovePowerToysSchTasks" After="RemoveFiles">
Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
<Custom Action="TelemetryLogInstallSuccess" After="InstallFinalize">
NOT Installed
</Custom>
<Custom Action="TelemetryLogUninstallSuccess" After="InstallFinalize">
Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
</InstallExecuteSequence>
<CustomAction Id="SetRegisterPowerToysSchTaskParam"
Property="RegisterPowerToysSchTask"
Value="[#PowerToys.exe]" />
<!-- Needs to Impersonate="no" and Execute="deferred" in order to run elevated. -->
<CustomAction Id="RegisterPowerToysSchTask"
Return="ignore"
Impersonate="no"
Execute="deferred"
BinaryKey="PTCustomActions"
DllEntry="CreateScheduledTaskCA"
/>
<!-- Needs to Impersonate="no" and Execute="deferred" in order to run elevated. -->
<CustomAction Id="RemovePowerToysSchTasks"
Return="ignore"
Impersonate="no"
Execute="deferred"
BinaryKey="PTCustomActions"
DllEntry="RemoveScheduledTasksCA"
/>
<CustomAction Id="TelemetryLogInstallSuccess"
Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="TelemetryLogInstallSuccessCA"
/>
<CustomAction Id="TelemetryLogInstallCancel"
Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="TelemetryLogInstallCancelCA"
/>
<CustomAction Id="TelemetryLogInstallFail"
Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="TelemetryLogInstallFailCA"
/>
<CustomAction Id="TelemetryLogUninstallSuccess"
Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="TelemetryLogUninstallSuccessCA"
/>
<CustomAction Id="TelemetryLogUninstallCancel"
Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="TelemetryLogUninstallCancelCA"
/>
<CustomAction Id="TelemetryLogUninstallFail"
Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="TelemetryLogUninstallFailCA"
/>
<CustomAction Id="TelemetryLogRepairCancel"
Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="TelemetryLogRepairCancelCA"
/>
<CustomAction Id="TelemetryLogRepairFail"
Return="ignore"
Impersonate="yes"
BinaryKey="PTCustomActions"
DllEntry="TelemetryLogRepairFailCA"
/>
<!-- Close 'PowerToys.exe' before uninstall-->
<Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
<util:CloseApplication CloseMessage="yes" Target="PowerToys.exe" ElevatedCloseMessage="yes" RebootPrompt="no" TerminateProcess="0" />
</Product>
<Fragment>
<Binary Id="PTCustomActions" SourceFile="$(var.PowerToysSetupCustomActions.TargetPath)" />
</Fragment>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLFOLDER" Name="PowerToys">
<Directory Id="SvgsInstallFolder" Name="svgs"/>
<Directory Id="ModulesInstallFolder" Name="modules"/>
<Directory Id="SettingsHtmlInstallFolder" Name="settings-html">
<Directory Id="SettingsHtmlDistInstallFolder" Name="dist"/>
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id ="ApplicationProgramsFolder" Name ="PowerToys"/>
</Directory>
<Directory Id="DesktopFolder" Name="Desktop"/>
</Directory>
</Fragment>
<Fragment>
<DirectoryRef Id="INSTALLFOLDER" FileSource="$(var.BinX64Dir)">
<Component Id="powertoys_exe" Guid="A2C66D91-3485-4D00-B04D-91844E6B345B" Win64="yes">
<File Id="PowerToys.exe" KeyPath="yes" Checksum="yes" />
</Component>
<Component Id="settings_exe" Guid="A5A461A9-7097-4CBA-9D39-3DBBB6B7B80C" Win64="yes">
<File Id="PowerToysSettings.exe" KeyPath="yes" Checksum="yes" />
</Component>
<Component Id="License_rtf" Guid="3E5AE43B-CFB4-449B-A346-94CAAFF3312E" Win64="yes">
<File Source="$(var.RepoDir)\License.rtf" Id="License.rtf" KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="SvgsInstallFolder" FileSource="$(var.BinX64Dir)\svgs\">
<Component Id="PowerToysSvgs" Guid="7C4D4EED-9338-423D-992C-DCE02F3E2D35" Win64="yes">
<File Source="$(var.BinX64Dir)\svgs\0.svg" />
<File Source="$(var.BinX64Dir)\svgs\1.svg" />
<File Source="$(var.BinX64Dir)\svgs\2.svg" />
<File Source="$(var.BinX64Dir)\svgs\3.svg" />
<File Source="$(var.BinX64Dir)\svgs\4.svg" />
<File Source="$(var.BinX64Dir)\svgs\5.svg" />
<File Source="$(var.BinX64Dir)\svgs\6.svg" />
<File Source="$(var.BinX64Dir)\svgs\7.svg" />
<File Source="$(var.BinX64Dir)\svgs\8.svg" />
<File Source="$(var.BinX64Dir)\svgs\9.svg" />
<File Source="$(var.BinX64Dir)\svgs\no_active_window.svg" />
<File Source="$(var.BinX64Dir)\svgs\overlay.svg" />
<File Source="$(var.BinX64Dir)\svgs\overlay_portrait.svg" />
</Component>
</DirectoryRef>
<DirectoryRef Id="ModulesInstallFolder" FileSource="$(var.BinX64Dir)\modules\">
<Component Id="Module_ShortcutGuide" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
<File Source="$(var.BinX64Dir)\modules\shortcut_guide.dll" KeyPath="yes" />
</Component>
<Component Id="Module_FancyZones" Guid="C6B5272E-6ED4-4B80-B0E7-2FF0355D8CF4" Win64="yes">
<File Source="$(var.BinX64Dir)\modules\fancyzones.dll" KeyPath="yes" />
<File Source="$(var.BinX64Dir)\modules\FancyZonesEditor.exe" />
<File Source="$(var.BinX64Dir)\modules\ControlzEx.dll" />
<File Source="$(var.BinX64Dir)\modules\MahApps.Metro.dll" />
<File Source="$(var.BinX64Dir)\modules\Microsoft.Xaml.Behaviors.dll" />
</Component>
</DirectoryRef>
<DirectoryRef Id="SettingsHtmlInstallFolder" FileSource="$(var.RepoDir)\editor\settings-html\">
<Component Id="settings_html" Guid="87881A99-E917-4B0D-B1D8-5C6EB9709F96" Win64="yes">
<File Source="$(var.RepoDir)\src\editor\settings-html\index.html" KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="SettingsHtmlDistInstallFolder" FileSource="$(var.RepoDir)\editor\settings-html\dist\">
<Component Id="settings_js_bundle" Guid="9EF539C1-2F50-421E-B074-C58ED3A9785C" Win64="yes">
<File Source="$(var.RepoDir)\src\editor\settings-html\dist\bundle.js" KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut" Guid="43184672-485D-4632-A16C-12D5E33B1F11">
<Condition>INSTALLSTARTMENUSHORTCUT</Condition>
<Shortcut Id="ApplicationStartMenuShortcut"
Name="PowerToys"
Description="PowerToys - Windows system utilities to maximize productivity"
Target="[!PowerToys.exe]"
WorkingDirectory="INSTALLFOLDER"
Icon="powertoys.ico"
IconIndex="0"/>
<RemoveFolder Id="RemoveApplicationProgramsFolder" Directory="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU"
Key="Software\[Manufacturer]\[ProductName]"
Name="startshorcutinstalled"
Type="integer"
Value="1"
KeyPath="yes"/>
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="DesktopFolder">
<Component Id="DesktopShortcut" Guid="87321F2B-CC48-4326-881E-9C62CC260DC8">
<Condition>INSTALLDESKTOPSHORTCUT</Condition>
<RegistryValue Root="HKCU"
Key="Software\[Manufacturer]\[ProductName]"
Name="desktopshorcutinstalled"
Type="integer"
Value="1"
KeyPath="yes"/>
<Shortcut Id="DesktopShortcutId"
Name="PowerToys"
Description="PowerToys - Windows system utilities to maximize productivity"
Target="[!PowerToys.exe]"
WorkingDirectory="INSTALLFOLDER"
Icon="powertoys.ico"
Directory="DesktopFolder"/>
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<ComponentRef Id="powertoys_exe" />
<ComponentRef Id="License_rtf" />
<ComponentRef Id="PowerToysSvgs" />
<ComponentRef Id="Module_ShortcutGuide" />
<ComponentRef Id="Module_FancyZones" />
<ComponentRef Id="ApplicationShortcut" />
<ComponentRef Id="DesktopShortcut" />
<ComponentRef Id="settings_exe" />
<ComponentRef Id="settings_html" />
<ComponentRef Id="settings_js_bundle" />
</ComponentGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,528 @@
#include "stdafx.h"
#define SECURITY_WIN32
#include <Security.h>
#pragma comment(lib, "Secur32.lib")
#include <Lmcons.h>
#include <comdef.h>
#include <taskschd.h>
#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsupp.lib")
#include <iostream>
#include <strutil.h>
#include <ProjectTelemetry.h>
using namespace std;
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"Microsoft.PowerToysInstaller",
// {e1d8165d-5cb6-5c74-3b51-bdfbfe4f7a3b}
(0xe1d8165d, 0x5cb6, 0x5c74, 0x3b, 0x51, 0xbd, 0xfb, 0xfe, 0x4f, 0x7a, 0x3b),
TraceLoggingOptionProjectTelemetry());
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
// Creates a Scheduled Task to run at logon for the current user.
// The path of the executable to run should be passed as the CustomActionData (Value).
// Based on the Task Scheduler Logon Trigger Example:
// https://docs.microsoft.com/en-us/windows/desktop/taskschd/logon-trigger-example--c---/
UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
TCHAR username_domain[USERNAME_DOMAIN_LEN];
TCHAR username[USERNAME_LEN];
std::wstring wstrTaskName;
ITaskService *pService = NULL;
ITaskFolder *pTaskFolder = NULL;
ITaskDefinition *pTask = NULL;
IRegistrationInfo *pRegInfo = NULL;
ITaskSettings *pSettings = NULL;
ITriggerCollection *pTriggerCollection = NULL;
IRegisteredTask *pRegisteredTask = NULL;
hr = WcaInitialize(hInstall, "CreateScheduledTaskCA");
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized.");
// ------------------------------------------------------
// Get the Domain/Username for the trigger.
//
// This action needs to run as the system to get elevated privileges from the installation,
// so GetUserNameEx can't be used to get the current user details.
// The USERNAME and USERDOMAIN environment variables are used instead.
if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) {
ExitWithLastError(hr, "Getting username failed: %x", hr);
}
if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) {
ExitWithLastError(hr, "Getting the user's domain failed: %x", hr);
}
wcscat_s(username_domain, L"\\");
wcscat_s(username_domain, username);
WcaLog(LOGMSG_STANDARD, "Current user detected: %ls", username_domain);
// Task Name.
wstrTaskName = L"Autorun for ";
wstrTaskName += username;
// Get the executable path passed to the custom action.
LPWSTR wszExecutablePath = NULL;
hr = WcaGetProperty(L"CustomActionData", &wszExecutablePath);
ExitOnFailure(hr, "Failed to get the executable path from CustomActionData.");
// COM and Security Initialization is expected to have been done by the MSI.
// It couldn't be done in the DLL, anyway.
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(),
_variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the PowerToys task folder. Creates it if it doesn't exist.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
if (FAILED(hr)) {
// Folder doesn't exist. Get the Root folder and create the PowerToys subfolder.
ITaskFolder *pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr);
hr = pRootFolder->CreateFolder(_bstr_t(L"\\PowerToys"), _variant_t(L""), &pTaskFolder);
if (FAILED(hr)) {
pRootFolder->Release();
ExitOnFailure(hr, "Cannot create PowerToys task folder: %x", hr);
}
WcaLog(LOGMSG_STANDARD, "PowerToys task folder created.");
}
// If the same task exists, remove it.
pTaskFolder->DeleteTask(_bstr_t(wstrTaskName.c_str()), 0);
// Create the task builder object to create the task.
hr = pService->NewTask(0, &pTask);
ExitOnFailure(hr, "Failed to create a task definition: %x", hr);
// ------------------------------------------------------
// Get the registration info for setting the identification.
hr = pTask->get_RegistrationInfo(&pRegInfo);
ExitOnFailure(hr, "Cannot get identification pointer: %x", hr);
hr = pRegInfo->put_Author(_bstr_t(username_domain));
ExitOnFailure(hr, "Cannot put identification info: %x", hr);
// ------------------------------------------------------
// Create the settings for the task
hr = pTask->get_Settings(&pSettings);
ExitOnFailure(hr, "Cannot get settings pointer: %x", hr);
hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: %x", hr);
hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: %x", hr);
hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited
ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr);
hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr);
// ------------------------------------------------------
// Get the trigger collection to insert the logon trigger.
hr = pTask->get_Triggers(&pTriggerCollection);
ExitOnFailure(hr, "Cannot get trigger collection: %x", hr);
// Add the logon trigger to the task.
ITrigger *pTrigger = NULL;
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
ExitOnFailure(hr, "Cannot create the trigger: %x", hr);
ILogonTrigger *pLogonTrigger = NULL;
hr = pTrigger->QueryInterface(
IID_ILogonTrigger, (void**)&pLogonTrigger);
pTrigger->Release();
ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: %x", hr);
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
if (FAILED(hr)) {
WcaLogError(hr, "Cannot put the trigger ID: %x", hr);
}
// Timing issues may make explorer not be started when the task runs.
// Add a little delay to mitigate this.
hr = pLogonTrigger->put_Delay(_bstr_t(L"PT03S"));
if (FAILED(hr)) {
WcaLogError(hr, "Cannot put the trigger delay: %x", hr);
}
// Define the user. The task will execute when the user logs on.
// The specified user must be a user on this computer.
hr = pLogonTrigger->put_UserId(_bstr_t(username_domain));
pLogonTrigger->Release();
ExitOnFailure(hr, "Cannot add user ID to logon trigger: %x", hr);
// ------------------------------------------------------
// Add an Action to the task. This task will execute the path passed to this custom action.
IActionCollection *pActionCollection = NULL;
// Get the task action collection pointer.
hr = pTask->get_Actions(&pActionCollection);
ExitOnFailure(hr, "Cannot get Task collection pointer: %x", hr);
// Create the action, specifying that it is an executable action.
IAction *pAction = NULL;
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
ExitOnFailure(hr, "Cannot create the action: %x", hr);
IExecAction *pExecAction = NULL;
// QI for the executable task pointer.
hr = pAction->QueryInterface(
IID_IExecAction, (void**)&pExecAction);
pAction->Release();
ExitOnFailure(hr, "QueryInterface call failed for IExecAction: %x", hr);
// Set the path of the executable to PowerToys (passed as CustomActionData).
hr = pExecAction->put_Path(_bstr_t(wszExecutablePath));
pExecAction->Release();
ExitOnFailure(hr, "Cannot set path of executable: %x", hr);
// ------------------------------------------------------
// Create the principal for the task
IPrincipal *pPrincipal = NULL;
hr = pTask->get_Principal(&pPrincipal);
ExitOnFailure(hr, "Cannot get principal pointer: %x", hr);
// Set up principal information:
hr = pPrincipal->put_Id(_bstr_t(L"Principal1"));
if (FAILED(hr)) {
WcaLogError(hr, "Cannot put the principal ID: %x", hr);
}
hr = pPrincipal->put_UserId(_bstr_t(username_domain));
if (FAILED(hr)) {
WcaLogError(hr, "Cannot put principal user Id: %x", hr);
}
hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
if (FAILED(hr)) {
WcaLogError(hr, "Cannot put principal logon type: %x", hr);
}
// Run the task with the highest available privileges.
hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);
pPrincipal->Release();
ExitOnFailure(hr, "Cannot put principal run level: %x", hr);
// ------------------------------------------------------
// Save the task in the PowerToys folder.
hr = pTaskFolder->RegisterTaskDefinition(
_bstr_t(wstrTaskName.c_str()),
pTask,
TASK_CREATE_OR_UPDATE,
_variant_t(username_domain),
_variant_t(),
TASK_LOGON_INTERACTIVE_TOKEN,
_variant_t(L""),
&pRegisteredTask);
ExitOnFailure(hr, "Error saving the Task : %x", hr);
WcaLog(LOGMSG_STANDARD, "Scheduled task created for the current user.");
LExit:
ReleaseStr(wszExecutablePath);
if (pService) pService->Release();
if (pTaskFolder) pTaskFolder->Release();
if (pTask) pTask->Release();
if (pRegInfo) pRegInfo->Release();
if (pSettings) pSettings->Release();
if (pTriggerCollection) pTriggerCollection->Release();
if (pRegisteredTask) pRegisteredTask->Release();
if (!SUCCEEDED(hr)) {
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Failed to create a scheduled task to start PowerToys at user login. You can re-try to create the scheduled task using the PowerToys settings."));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
}
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
// Removes all Scheduled Tasks in the PowerToys folder and deletes the folder afterwards.
// Based on the Task Scheduler Displaying Task Names and State example:
// https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/displaying-task-names-and-state--c---/
UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
ITaskService *pService = NULL;
ITaskFolder *pTaskFolder = NULL;
IRegisteredTaskCollection* pTaskCollection = NULL;
hr = WcaInitialize(hInstall, "RemoveScheduledTasksCA");
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized.");
// COM and Security Initialization is expected to have been done by the MSI.
// It couldn't be done in the DLL, anyway.
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskService,
(void**)&pService);
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(),
_variant_t(), _variant_t());
ExitOnFailure(hr, "ITaskService::Connect failed: %x", hr);
// ------------------------------------------------------
// Get the PowerToys task folder.
hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder);
if (FAILED(hr)) {
// Folder doesn't exist. No need to delete anything.
WcaLog(LOGMSG_STANDARD, "The PowerToys scheduled task folder wasn't found. Nothing to delete.");
hr = S_OK;
ExitFunction();
}
// -------------------------------------------------------
// Get the registered tasks in the folder.
hr = pTaskFolder->GetTasks(TASK_ENUM_HIDDEN, &pTaskCollection);
ExitOnFailure(hr, "Cannot get the registered tasks: %x", hr);
LONG numTasks = 0;
hr = pTaskCollection->get_Count(&numTasks);
for (LONG i = 0; i < numTasks; i++) {
// Delete all the tasks found.
// If some tasks can't be deleted, the folder won't be deleted later and the user will still be notified.
IRegisteredTask* pRegisteredTask = NULL;
hr = pTaskCollection->get_Item(_variant_t(i + 1), &pRegisteredTask);
if (SUCCEEDED(hr)) {
BSTR taskName = NULL;
hr = pRegisteredTask->get_Name(&taskName);
if (SUCCEEDED(hr)) {
hr = pTaskFolder->DeleteTask(taskName, NULL);
if (FAILED(hr)) {
WcaLogError(hr, "Cannot delete the '%S' task: %x", taskName, hr);
}
SysFreeString(taskName);
} else {
WcaLogError(hr, "Cannot get the registered task name: %x", hr);
}
pRegisteredTask->Release();
} else {
WcaLogError(hr, "Cannot get the registered task item at index=%d: %x", i + 1, hr);
}
}
// ------------------------------------------------------
// Get the pointer to the root task folder and delete the PowerToys subfolder.
ITaskFolder *pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
ExitOnFailure(hr, "Cannot get Root Folder pointer: %x", hr);
hr = pRootFolder->DeleteFolder(_bstr_t(L"PowerToys"), NULL);
pRootFolder->Release();
ExitOnFailure(hr, "Cannot delete the PowerToys folder: %x", hr);
WcaLog(LOGMSG_STANDARD, "Deleted the PowerToys Task Scheduler folder.");
LExit:
if (pService) pService->Release();
if (pTaskFolder) pTaskFolder->Release();
if (pTaskCollection) pTaskCollection->Release();
if (!SUCCEEDED(hr)) {
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Failed to remove the PowerToys folder from the scheduled task. These can be removed manually later."));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
}
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TelemetryLogInstallSuccessCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "TelemetryLogInstallSuccessCA");
ExitOnFailure(hr, "Failed to initialize");
TraceLoggingWrite(
g_hProvider,
"Install::Success",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TelemetryLogInstallCancelCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "TelemetryLogInstallCancelCA");
ExitOnFailure(hr, "Failed to initialize");
TraceLoggingWrite(
g_hProvider,
"Install::Cancel",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TelemetryLogInstallFailCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "TelemetryLogInstallFailCA");
ExitOnFailure(hr, "Failed to initialize");
TraceLoggingWrite(
g_hProvider,
"Install::Fail",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TelemetryLogUninstallSuccessCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "TelemetryLogUninstallSuccessCA");
ExitOnFailure(hr, "Failed to initialize");
TraceLoggingWrite(
g_hProvider,
"Uninstall::Success",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TelemetryLogUninstallCancelCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "TelemetryLogUninstallCancelCA");
ExitOnFailure(hr, "Failed to initialize");
TraceLoggingWrite(
g_hProvider,
"Uninstall::Cancel",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TelemetryLogUninstallFailCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "TelemetryLogUninstallFailCA");
ExitOnFailure(hr, "Failed to initialize");
TraceLoggingWrite(
g_hProvider,
"Uninstall::Fail",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TelemetryLogRepairCancelCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "TelemetryLogRepairCancelCA");
ExitOnFailure(hr, "Failed to initialize");
TraceLoggingWrite(
g_hProvider,
"Repair::Cancel",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall TelemetryLogRepairFailCA(MSIHANDLE hInstall) {
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
hr = WcaInitialize(hInstall, "TelemetryLogRepairFailCA");
ExitOnFailure(hr, "Failed to initialize");
TraceLoggingWrite(
g_hProvider,
"Repair::Fail",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
// DllMain - Initialize and cleanup WiX custom action utils.
extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID) {
switch (ulReason) {
case DLL_PROCESS_ATTACH:
WcaGlobalInitialize(hInst);
TraceLoggingRegister(g_hProvider);
break;
case DLL_PROCESS_DETACH:
TraceLoggingUnregister(g_hProvider);
WcaGlobalFinalize();
break;
}
return TRUE;
}

View file

@ -0,0 +1,13 @@
LIBRARY "PowerToysSetupCustomActions"
EXPORTS
CreateScheduledTaskCA
RemoveScheduledTasksCA
TelemetryLogInstallSuccessCA
TelemetryLogInstallCancelCA
TelemetryLogInstallFailCA
TelemetryLogUninstallSuccessCA
TelemetryLogUninstallCancelCA
TelemetryLogUninstallFailCA
TelemetryLogRepairCancelCA
TelemetryLogRepairFailCA

View file

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{32f3882b-f2d6-4586-b5ed-11e39e522bd3}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerToysSetupCustomActions</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>inc;telemetry;$(WIX)sdk\$(WixPlatformToolset)\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>CustomAction.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<UACExecutionLevel>HighestAvailable</UACExecutionLevel>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>inc;telemetry;$(WIX)sdk\$(WixPlatformToolset)\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;CUSTOMACTIONTEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ModuleDefinitionFile>CustomAction.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX64</TargetMachine>
<UACExecutionLevel>HighestAvailable</UACExecutionLevel>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="CustomAction.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="CustomAction.def" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="Telemetry\ProjectTelemetry.h" />
<ClInclude Include="Telemetry\TraceLoggingDefines.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(WixNativeCATargetsPath)" Condition=" '$(WixNativeCATargetsPath)' != '' " />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.NativeCA.targets" Condition=" '$(WixNativeCATargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.NativeCA.targets') " />
<Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixNativeCATargetsImported)' != 'true' ">
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
</Target>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="CustomAction.cpp" />
<ClCompile Include="stdafx.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="Telemetry\ProjectTelemetry.h">
<Filter>Telemetry</Filter>
</ClInclude>
<ClInclude Include="Telemetry\TraceLoggingDefines.h">
<Filter>Telemetry</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CustomAction.def" />
</ItemGroup>
<ItemGroup>
<Filter Include="Telemetry">
<UniqueIdentifier>{6e73ce5d-e715-4e7e-b796-c5d180b07ff2}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View file

@ -0,0 +1,6 @@
#pragma once
#include <TraceLoggingProvider.h>
#include <TraceLoggingDefines.h>
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);

View file

@ -0,0 +1,6 @@
#pragma once
#define TraceLoggingOptionProjectTelemetry() TraceLoggingOptionGroup(0x42749043, 0x438c, 0x46a2, 0x82, 0xbe, 0xc6, 0xcb, 0xeb, 0x19, 0x2f, 0xf2)
#define ProjectTelemetryPrivacyDataTag(tag) TraceLoggingUInt64((tag), "Ignore")
#define ProjectTelemetryTag_ProductAndServicePerformance 0x0u
#define PROJECT_KEYWORD_MEASURE 0x0

View file

@ -0,0 +1,4 @@
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View file

@ -0,0 +1,13 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
#include <strsafe.h>
#include <msiquery.h>
// WiX Header Files:
#include <wcautil.h>
// TODO: reference additional headers your program requires here

7
installer/README.md Normal file
View file

@ -0,0 +1,7 @@
# PowerToys Setup Project
## Build instructions
* Install the [WiX Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=RobMensching.WiXToolset).
* Install the [WiX Toolset build tools](https://wixtoolset.org/releases/) in the development machine.
* Open `powertoys.sln`, select the "Release" and "x64" configurations and build the `PowerToysSetup` project.
* The resulting installer will be built to `PowerToysSetup\bin\Release\PowerToysSetup.msi`.

8
src/README.md Normal file
View file

@ -0,0 +1,8 @@
# PowerToys Source Code
## Code organization
The PowerToys are splitted into DLLs for each PowerToy module ([`modules`](/src/modules) folder), and an executable ([`runner`](/src/runner) folder) that loads and manages those DLLs.
The settings window is a separate executable, contained in [`editor`](/src/editor) folder. In utilizes a WebView to display a HTML-based settings window (contained in [`settings-web`](/src/settings-web) folder).
The [`common`](/src/common) contains code for a static libary with helper functions, used by both the runner and the PowerToys modules.

48
src/common/README.md Normal file
View file

@ -0,0 +1,48 @@
# Introduction
The common lib, as the name suggests, contains code shared by multiple PowerToys components and modules.
# Classes and structures
#### class Animation: [header](./animation.h) [source](./animation.cpp)
Animation helper class with two easing-in animations: linear and exponential.
#### class AsyncMessageQueue: [header](./async_message_queue.h)
Header-only asynchronous message queue. Used by `TwoWayPipeMessageIPC`.
#### class TwoWayPipeMessageIPC: [header](./two_way_pipe_message_ipc.h)
Header-only asynchronous IPC messaging class. Used by the runner to communicate with the settings window.
#### class D2DSVG: [header](./d2d_svg.h) [source](./d2d_svg.cpp)
Class for loading, rendering and for some basic modifications of SVG graphics.
#### class D2DText: [header](./d2d_text.h) [source](./d2d_text.cpp)
Class for rendering text using DirectX.
#### class D2DWindow: [header](./d2d_window.h) [source](./d2d_window.cpp)
Base class for creating borderless windows, with DirectX enabled rendering pipeline.
#### class DPIAware: [header](./dpi_aware.h) [source](./dpi_aware.cpp)
Helper class for creating DPI-aware applications.
#### struct MonitorInfo: [header](./monitors.h) [source](./monitors.cpp)
Class for obtaining information about physical displays connected to the machine.
#### class Settings, class PowerToyValues, class CustomActionObject: [header](./settings_objects.h) [source](./settings_objects.cpp)
Classes used to define settings screens for the PowerToys modules.
#### class Tasklist: [header](./tasklist_positions.h) [source](./tasklist_positions.cpp)
Class that can detect the position of the windows buttons on the taskbar. It also detects which window will react to pressing `WinKey + number`.
#### struct WindowsColors: [header](./windows_colors.h) [source](./windows_colors.cpp)
Class for detecting the current Windows color scheme.
# Helpers
#### Common helpers: [header](./common.h) [source](./common.cpp)
Various helper functions.
#### Settings helpers: [header](./settings_helpers.h)
Helper methods for the settings.
#### Start visible helper: [header](./start_visible.h) [source](./start_visible.cpp)
Contains function to test if the Start menu is visible.

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<WindowsPerformanceRecorder Version="1.0" Author="Microsoft Corporation" Copyright="Microsoft Corporation" Company="Microsoft Corporation">
<Profiles>
<EventCollector Id="EventCollector_Microsoft.PowerToys" Name="Microsoft.PowerToys">
<BufferSize Value="64" />
<Buffers Value="4" />
</EventCollector>
<EventProvider Id="EventProvider_Microsoft.PowerToys" Name="38e8889b-9731-53f5-e901-e8a7c1753074" />
<Profile Id="Microsoft.PowerToys.Verbose.File" Name="Microsoft.PowerToys" Description="Microsoft.PowerToys" LoggingMode="File" DetailLevel="Verbose">
<Collectors>
<EventCollectorId Value="EventCollector_Microsoft.PowerToys">
<EventProviders>
<EventProviderId Value="EventProvider_Microsoft.PowerToys" />
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
<Profile Id="Microsoft.PowerToys.Light.File" Name="Microsoft.PowerToys" Description="Microsoft.PowerToys" Base="Microsoft.PowerToys.Verbose.File" LoggingMode="File" DetailLevel="Light" />
<Profile Id="Microsoft.PowerToys.Verbose.Memory" Name="Microsoft.PowerToys" Description="Microsoft.PowerToys" Base="Microsoft.PowerToys.Verbose.File" LoggingMode="Memory" DetailLevel="Verbose" />
<Profile Id="Microsoft.PowerToys.Light.Memory" Name="Microsoft.PowerToys" Description="Microsoft.PowerToys" Base="Microsoft.PowerToys.Verbose.File" LoggingMode="Memory" DetailLevel="Light" />
</Profiles>
</WindowsPerformanceRecorder>

View file

@ -0,0 +1,6 @@
#pragma once
#include <TraceLoggingProvider.h>
#include <TraceLoggingDefines.h>
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);

View file

@ -0,0 +1,6 @@
#pragma once
#define TraceLoggingOptionProjectTelemetry() TraceLoggingOptionGroup(0x42749043, 0x438c, 0x46a2, 0x82, 0xbe, 0xc6, 0xcb, 0xeb, 0x19, 0x2f, 0xf2)
#define ProjectTelemetryPrivacyDataTag(tag) TraceLoggingUInt64((tag), "Ignore")
#define ProjectTelemetryTag_ProductAndServicePerformance 0x0u
#define PROJECT_KEYWORD_MEASURE 0x0

View file

@ -0,0 +1,25 @@
# Overview
Telemetry from the PowerToys provider can be captured using the PowerToys.wprp file and WPR.
## Starting trace capture
To capture a trace for the PowerToys provider, run the following:
`wpr.exe -start "PowerToys.wprp"`
## Stopping trace capture
To capture a trace for the PowerToys provider, run the following:
`wpr.exe -Stop "Trace.etl"`
## Viewing Events
Open the trace.etl file in WPA.
## Additional Resources
[Tracelogging on MSDN](https://docs.microsoft.com/en-us/windows/win32/tracelogging/trace-logging-portal)
[Recording and Viewing Events](https://docs.microsoft.com/en-us/windows/win32/tracelogging/tracelogging-record-and-display-tracelogging-events)

View file

@ -0,0 +1,62 @@
#include "pch.h"
#include <settings_objects.h>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace PowerToysSettings;
namespace UnitTestsCommonLib
{
TEST_CLASS(SettingsUnitTests)
{
private:
const std::wstring m_json = L"{\"name\":\"Module Name\",\"properties\" : {\"bool_toggle_true\":{\"value\":true},\"bool_toggle_false\":{\"value\":false},\"color_picker\" : {\"value\":\"#ff8d12\"},\"int_spinner\" : {\"value\":10},\"string_text\" : {\"value\":\"a quick fox\"}},\"version\" : \"1.0\" }";
public:
TEST_METHOD(LoadFromJsonBoolTrue)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
Assert::IsTrue(values.is_bool_value(L"bool_toggle_true"));
bool value = values.get_bool_value(L"bool_toggle_true");
Assert::AreEqual(true, value);
}
TEST_METHOD(LoadFromJsonBoolFalse)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
Assert::IsTrue(values.is_bool_value(L"bool_toggle_false"));
bool value = values.get_bool_value(L"bool_toggle_false");
Assert::AreEqual(false, value);
}
TEST_METHOD(LoadFromJsonInt)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
Assert::IsTrue(values.is_int_value(L"int_spinner"));
int value = values.get_int_value(L"int_spinner");
Assert::AreEqual(10, value);
}
TEST_METHOD(LoadFromJsonString)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
Assert::IsTrue(values.is_string_value(L"string_text"));
std::wstring value = values.get_string_value(L"string_text");
std::wstring expected = L"a quick fox";
Assert::AreEqual(expected, value);
}
TEST_METHOD(LoadFromJsonColorPicker)
{
PowerToyValues values = PowerToyValues::from_json_string(m_json);
Assert::IsTrue(values.is_string_value(L"color_picker"));
std::wstring value = values.get_string_value(L"color_picker");
std::wstring expected = L"#ff8d12";
Assert::AreEqual(expected, value);
}
};
}

View file

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{1A066C63-64B3-45F8-92FE-664E1CCE8077}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>UnitTestsCommonLib</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectSubType>NativeUnitTestProject</ProjectSubType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\;..\Telemetry;..\..\..\deps\cpprestsdk\include;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>RuntimeObject.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;..\;..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>RuntimeObject.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="Settings.Tests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\common.vcxproj">
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Settings.Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View file

@ -0,0 +1,16 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include <Windows.h>
#include <winrt\base.h>
#include "CppUnitTest.h"
#endif //PCH_H

43
src/common/animation.cpp Normal file
View file

@ -0,0 +1,43 @@
#include "pch.h"
#include "animation.h"
Animation::Animation(double duration, double start, double stop) :
start_value(start), end_value(stop), duration(duration), start(std::chrono::high_resolution_clock::now()) { }
void Animation::reset() {
start = std::chrono::high_resolution_clock::now();
}
void Animation::reset(double duration) {
this->duration = duration;
reset();
}
void Animation::reset(double duration, double start, double stop) {
start_value = start;
end_value = stop;
reset(duration);
}
static double ease_out_expo(double t) {
return 1 - pow(2, -8 * t);
}
double Animation::apply_animation_function(double t, AnimFunctions apply_function) const {
switch (apply_function) {
case EASE_OUT_EXPO:
return ease_out_expo(t);
case LINEAR:
default:
return t;
}
}
double Animation::value(AnimFunctions apply_function) const {
auto anim_duration = std::chrono::high_resolution_clock::now() - start;
double t = std::chrono::duration<double>(anim_duration).count() / duration;
if (t >= 1)
return end_value;
return start_value + (end_value - start_value) * apply_animation_function(t, apply_function);
}
bool Animation::done() const {
return std::chrono::high_resolution_clock::now() - start >= std::chrono::duration<double>(duration);
}

31
src/common/animation.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include <chrono>
/*
Usage:
When creating animation contstructor takes one parameter - how long
should the animation take in seconds.
Call reset() when starting animation.
When redering, call value() to get value from 0 to 1 - depending on animation
progress.
*/
class Animation {
public:
enum AnimFunctions {
LINEAR = 0,
EASE_OUT_EXPO
};
Animation(double duration = 1, double start = 0, double stop = 1);
void reset();
void reset(double duration);
void reset(double duration, double start, double stop);
double value(AnimFunctions apply_function) const;
bool done() const;
private:
double apply_animation_function(double t, AnimFunctions apply_function) const;
std::chrono::high_resolution_clock::time_point start;
double start_value, end_value, duration;
};

View file

@ -0,0 +1,47 @@
#pragma once
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <string>
class AsyncMessageQueue {
private:
std::mutex queue_mutex;
std::queue<std::wstring> message_queue;
std::condition_variable message_ready;
bool interrupted = false;
//Disable copy
AsyncMessageQueue(const AsyncMessageQueue&);
AsyncMessageQueue& operator=(const AsyncMessageQueue&);
public:
AsyncMessageQueue() {
}
void queue_message(std::wstring message) {
this->queue_mutex.lock();
this->message_queue.push(message);
this->queue_mutex.unlock();
this->message_ready.notify_one();
}
std::wstring pop_message() {
std::unique_lock<std::mutex> lock(this->queue_mutex);
while (message_queue.empty() && !this->interrupted) {
this->message_ready.wait(lock);
}
if (this->interrupted) {
//Just returns a empty string if the queue was interrupted.
return std::wstring(L"");
}
std::wstring message = this->message_queue.front();
this->message_queue.pop();
return message;
}
void interrupt() {
this->queue_mutex.lock();
this->interrupted = true;
this->queue_mutex.unlock();
this->message_ready.notify_all();
}
};

152
src/common/common.cpp Normal file
View file

@ -0,0 +1,152 @@
#include "pch.h"
#include "common.h"
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#include <strsafe.h>
std::optional<RECT> get_button_pos(HWND hwnd) {
RECT button;
if (DwmGetWindowAttribute(hwnd, DWMWA_CAPTION_BUTTON_BOUNDS, &button, sizeof(RECT)) == S_OK) {
return button;
} else {
return {};
}
}
std::optional<RECT> get_window_pos(HWND hwnd) {
RECT window;
if (DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &window, sizeof(window)) == S_OK) {
return window;
} else {
return {};
}
}
std::optional<POINT> get_mouse_pos() {
POINT point;
if (GetCursorPos(&point) == 0) {
return {};
} else {
return point;
}
}
int width(const RECT& rect) {
return rect.right - rect.left;
}
int height(const RECT& rect) {
return rect.bottom - rect.top;
}
bool operator<(const RECT& lhs, const RECT& rhs) {
auto lhs_tuple = std::make_tuple(lhs.left, lhs.right, lhs.top, lhs.bottom);
auto rhs_tuple = std::make_tuple(rhs.left, rhs.right, rhs.top, rhs.bottom);
return lhs_tuple < rhs_tuple;
}
RECT keep_rect_inside_rect(const RECT& small_rect, const RECT& big_rect) {
RECT result = small_rect;
if ((result.right - result.left) > (big_rect.right - big_rect.left)) {
// small_rect is too big horizontally. resize it.
result.right = big_rect.right;
result.left = big_rect.left;
} else {
if (result.right > big_rect.right) {
// move the rect left.
result.left -= result.right-big_rect.right;
result.right -= result.right-big_rect.right;
}
if (result.left < big_rect.left) {
// move the rect right.
result.right += big_rect.left-result.left;
result.left += big_rect.left-result.left;
}
}
if ((result.bottom - result.top) > (big_rect.bottom - big_rect.top)) {
// small_rect is too big vertically. resize it.
result.bottom = big_rect.bottom;
result.top = big_rect.top;
} else {
if (result.bottom > big_rect.bottom) {
// move the rect up.
result.top -= result.bottom-big_rect.bottom;
result.bottom -= result.bottom-big_rect.bottom;
}
if (result.top < big_rect.top) {
// move the rect down.
result.bottom += big_rect.top-result.top;
result.top += big_rect.top-result.top;
}
}
return result;
}
int run_message_loop() {
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
void show_last_error_message(LPCWSTR lpszFunction, DWORD dw) {
// Retrieve the system error message for the error code
LPWSTR lpMsgBuf = NULL;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
lpMsgBuf,
0, NULL) > 0) {
// Display the error message and exit the process
LPWSTR lpDisplayBuf = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (lstrlenW(lpMsgBuf) + lstrlenW(lpszFunction) + 40) * sizeof(WCHAR));
if (lpDisplayBuf != NULL) {
StringCchPrintfW(lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(WCHAR),
L"%s failed with error %d: %s",
lpszFunction, dw, lpMsgBuf);
MessageBoxW(NULL, (LPCTSTR)lpDisplayBuf, L"Error", MB_OK);
LocalFree(lpDisplayBuf);
}
LocalFree(lpMsgBuf);
}
}
WindowState get_window_state(HWND hwnd) {
WINDOWPLACEMENT placement;
placement.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(hwnd, &placement) == 0) {
return UNKNONW;
}
if (placement.showCmd == SW_MINIMIZE || placement.showCmd == SW_SHOWMINIMIZED || IsIconic(hwnd)) {
return MINIMIZED;
}
if (placement.showCmd == SW_MAXIMIZE || placement.showCmd == SW_SHOWMAXIMIZED) {
return MAXIMIZED;
}
auto rectp = get_window_pos(hwnd);
if (!rectp) {
return UNKNONW;
}
auto rect = *rectp;
MONITORINFO monitor;
monitor.cbSize = sizeof(MONITORINFO);
auto h_monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
GetMonitorInfo(h_monitor, &monitor);
bool top_left = monitor.rcWork.top == rect.top && monitor.rcWork.left == rect.left;
bool bottom_left = monitor.rcWork.bottom == rect.bottom && monitor.rcWork.left == rect.left;
bool top_right = monitor.rcWork.top == rect.top && monitor.rcWork.right == rect.right;
bool bottom_right = monitor.rcWork.bottom == rect.bottom && monitor.rcWork.right == rect.right;
if (top_left && bottom_left) return SNAPED_LEFT;
if (top_left) return SNAPED_TOP_LEFT;
if (bottom_left) return SNAPED_BOTTOM_LEFT;
if (top_right && bottom_right) return SNAPED_RIGHT;
if (top_right) return SNAPED_TOP_RIGHT;
if (bottom_right) return SNAPED_BOTTOM_RIGHT;
return RESTORED;
}

36
src/common/common.h Normal file
View file

@ -0,0 +1,36 @@
#pragma once
#include <optional>
#include <Windows.h>
// Returns RECT with positions of the minmize/maximize buttons of the given window.
// Does not always work, since some apps draw custom toolbars.
std::optional<RECT> get_button_pos(HWND hwnd);
// Gets position of given window.
std::optional<RECT> get_window_pos(HWND hwnd);
// Gets mouse postion.
std::optional<POINT> get_mouse_pos();
// Calculate sizes
int width(const RECT& rect);
int height(const RECT& rect);
// Compare rects
bool operator<(const RECT& lhs, const RECT& rhs);
// Moves and/or resizes small_rect to fit inside big_rect.
RECT keep_rect_inside_rect(const RECT& small_rect, const RECT& big_rect);
// Initializes and runs windows message loop
int run_message_loop();
void show_last_error_message(LPCWSTR lpszFunction, DWORD dw);
enum WindowState {
UNKNONW,
MINIMIZED,
MAXIMIZED,
SNAPED_TOP_LEFT,
SNAPED_LEFT,
SNAPED_BOTTOM_LEFT,
SNAPED_TOP_RIGHT,
SNAPED_RIGHT,
SNAPED_BOTTOM_RIGHT,
RESTORED
};
WindowState get_window_state(HWND hwnd);

138
src/common/common.vcxproj Normal file
View file

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{74485049-C722-400F-ABE5-86AC52D929B3}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>common</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>common</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>inc;telemetry;..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>inc;telemetry;..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="animation.h" />
<ClInclude Include="async_message_queue.h" />
<ClInclude Include="d2d_svg.h" />
<ClInclude Include="d2d_text.h" />
<ClInclude Include="d2d_window.h" />
<ClInclude Include="dpi_aware.h" />
<ClInclude Include="monitors.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="settings_helpers.h" />
<ClInclude Include="settings_objects.h" />
<ClInclude Include="start_visible.h" />
<ClInclude Include="tasklist_positions.h" />
<ClInclude Include="common.h" />
<ClInclude Include="Telemetry\ProjectTelemetry.h" />
<ClInclude Include="Telemetry\TraceLoggingDefines.h" />
<ClInclude Include="two_way_pipe_message_ipc.h" />
<ClInclude Include="windows_colors.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="animation.cpp" />
<ClCompile Include="d2d_svg.cpp" />
<ClCompile Include="d2d_text.cpp" />
<ClCompile Include="d2d_window.cpp" />
<ClCompile Include="dpi_aware.cpp" />
<ClCompile Include="monitors.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="settings_helpers.cpp" />
<ClCompile Include="settings_objects.cpp" />
<ClCompile Include="start_visible.cpp" />
<ClCompile Include="tasklist_positions.cpp" />
<ClCompile Include="common.cpp" />
<ClCompile Include="windows_colors.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\deps\cpprestsdk\cpprestsdk.vcxproj">
<Project>{4e577735-dfab-41af-8a6e-b6e8872a2928}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Header Files\Direct2D">
<UniqueIdentifier>{ed0f9961-6b12-408b-8dbc-fed779a557ac}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Telemetry">
<UniqueIdentifier>{3e9f944e-5d97-4a28-8865-2eff3a3568e7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="d2d_svg.h">
<Filter>Header Files\Direct2D</Filter>
</ClInclude>
<ClInclude Include="d2d_text.h">
<Filter>Header Files\Direct2D</Filter>
</ClInclude>
<ClInclude Include="d2d_window.h">
<Filter>Header Files\Direct2D</Filter>
</ClInclude>
<ClInclude Include="pch.h" />
<ClInclude Include="animation.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="monitors.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="tasklist_positions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="windows_colors.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="start_visible.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Telemetry\ProjectTelemetry.h">
<Filter>Header Files\Telemetry</Filter>
</ClInclude>
<ClInclude Include="Telemetry\TraceLoggingDefines.h">
<Filter>Header Files\Telemetry</Filter>
</ClInclude>
<ClInclude Include="two_way_pipe_message_ipc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="async_message_queue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="settings_helpers.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="settings_objects.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="dpi_aware.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="d2d_svg.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="d2d_text.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="d2d_window.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp" />
<ClCompile Include="animation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="monitors.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tasklist_positions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="windows_colors.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="start_visible.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="common.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="settings_helpers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="settings_objects.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dpi_aware.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

105
src/common/d2d_svg.cpp Normal file
View file

@ -0,0 +1,105 @@
#include "pch.h"
#include "d2d_svg.h"
D2DSVG& D2DSVG::load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc) {
svg = nullptr;
winrt::com_ptr<IStream> svg_stream;
winrt::check_hresult(SHCreateStreamOnFileEx(filename.c_str(),
STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE,
nullptr,
svg_stream.put()));
winrt::check_hresult(d2d_dc->CreateSvgDocument(
svg_stream.get(),
D2D1::SizeF(1, 1),
svg.put()));
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
float tmp;
winrt::check_hresult(root->GetAttributeValue(L"width", &tmp));
svg_width = (int)tmp;
winrt::check_hresult(root->GetAttributeValue(L"height", &tmp));
svg_height = (int)tmp;
return *this;
}
D2DSVG& D2DSVG::resize(int x, int y, int width, int height, float fill, float max_scale) {
// Center
transform = D2D1::Matrix3x2F::Identity();
transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f);
float h_scale = fill * height / svg_height;
float v_scale = fill * width / svg_width;
used_scale = min(h_scale, v_scale);
if (max_scale > 0) {
used_scale = min(used_scale, max_scale);
}
transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f));
transform = transform * D2D1::Matrix3x2F::Translation((float)x, (float)y);
return *this;
}
D2DSVG& D2DSVG::recolor(uint32_t oldcolor, uint32_t newcolor) {
auto new_color = D2D1::ColorF(newcolor & 0xFFFFFF, 1);
auto old_color = D2D1::ColorF(oldcolor & 0xFFFFFF, 1);
std::function<void(ID2D1SvgElement* element)> recurse = [&](ID2D1SvgElement* element) {
if (!element)
return;
if (element->IsAttributeSpecified(L"fill")) {
D2D1_COLOR_F elem_fill;
winrt::com_ptr<ID2D1SvgPaint> paint;
element->GetAttributeValue(L"fill", paint.put());
paint->GetColor(&elem_fill);
if (elem_fill.r == old_color.r && elem_fill.g == old_color.g && elem_fill.b == old_color.b) {
winrt::check_hresult(element->SetAttributeValue(L"fill", new_color));
}
}
winrt::com_ptr<ID2D1SvgElement> sub;
element->GetFirstChild(sub.put());
while (sub) {
recurse(sub.get());
winrt::com_ptr<ID2D1SvgElement> next;
element->GetNextChild(sub.get(), next.put());
sub = next;
}
};
winrt::com_ptr<ID2D1SvgElement> root;
svg->GetRoot(root.put());
recurse(root.get());
return *this;
}
D2DSVG& D2DSVG::render(ID2D1DeviceContext5* d2d_dc) {
D2D1_MATRIX_3X2_F current;
d2d_dc->GetTransform(&current);
d2d_dc->SetTransform(transform * current);
d2d_dc->DrawSvgDocument(svg.get());
d2d_dc->SetTransform(current);
return *this;
}
D2DSVG& D2DSVG::toggle_element(const wchar_t* id, bool visible) {
winrt::com_ptr<ID2D1SvgElement> element;
if (svg->FindElementById(id, element.put()) != S_OK)
return *this;
if (!element)
return *this;
element->SetAttributeValue(L"display", visible ? D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_INLINE : D2D1_SVG_DISPLAY::D2D1_SVG_DISPLAY_NONE);
return *this;
}
winrt::com_ptr<ID2D1SvgElement> D2DSVG::find_element(const std::wstring& id) {
winrt::com_ptr< ID2D1SvgElement> element;
winrt::check_hresult(svg->FindElementById(id.c_str(), element.put()));
return element;
}
D2D1_RECT_F D2DSVG::rescale(D2D1_RECT_F rect) {
D2D1_RECT_F result;
auto src = reinterpret_cast<D2D1_POINT_2F*>(&rect);
auto dst = reinterpret_cast<D2D1_POINT_2F*>(&result);
dst[0] = src[0] * transform;
dst[1] = src[1] * transform;
return result;
}

24
src/common/d2d_svg.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include <d2d1_3.h>
#include <d2d1_3helper.h>
#include <winrt/base.h>
#include <string>
class D2DSVG {
public:
D2DSVG& load(const std::wstring& filename, ID2D1DeviceContext5* d2d_dc);
D2DSVG& resize(int x, int y, int width, int height, float fill, float max_scale = -1.0f);
D2DSVG& render(ID2D1DeviceContext5* d2d_dc);
D2DSVG& recolor(uint32_t oldcolor, uint32_t newcolor);
float get_scale() const { return used_scale; }
int width() const { return svg_width; }
int height() const { return svg_height; }
D2DSVG& toggle_element(const wchar_t* id, bool visible);
winrt::com_ptr<ID2D1SvgElement> find_element(const std::wstring& id);
D2D1_RECT_F rescale(D2D1_RECT_F rect);
protected:
float used_scale = 1.0f;
winrt::com_ptr<ID2D1SvgDocument> svg;
int svg_width = -1, svg_height = -1;
D2D1::Matrix3x2F transform;
};

48
src/common/d2d_text.cpp Normal file
View file

@ -0,0 +1,48 @@
#include "pch.h"
#include "d2d_text.h"
D2DText::D2DText(float text_size, float scale) {
winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(factory), reinterpret_cast<IUnknown**>(factory.put_void())));
resize(text_size, scale);
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
}
D2DText & D2DText::resize(float text_size, float scale) {
format = nullptr;
winrt::check_hresult(factory->CreateTextFormat(L"Segoe UI",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
text_size * scale,
L"en-us",
format.put()));
winrt::check_hresult(format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
return *this;
}
D2DText & D2DText::set_aligment_left() {
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING));
return *this;
}
D2DText & D2DText::set_aligment_center() {
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
return *this;
}
D2DText & D2DText::set_aligment_right() {
winrt::check_hresult(format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING));
return *this;
}
void D2DText::write(ID2D1DeviceContext5 * d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text) {
winrt::com_ptr<ID2D1SolidColorBrush> brush;
d2d_dc->CreateSolidColorBrush(color, brush.put());
d2d_dc->DrawText(text.c_str(),
(UINT32)text.length(),
format.get(),
rect,
brush.get());
}

16
src/common/d2d_text.h Normal file
View file

@ -0,0 +1,16 @@
#pragma once
#include <winrt/base.h>
#include <dwrite.h>
class D2DText {
public:
D2DText(float text_size = 15.0f, float scale = 1.0f);
D2DText& resize(float text_size, float scale);
D2DText& set_aligment_left();
D2DText& set_aligment_center();
D2DText& set_aligment_right();
void write(ID2D1DeviceContext5* d2d_dc, D2D1_COLOR_F color, D2D1_RECT_F rect, std::wstring text);
private:
winrt::com_ptr<IDWriteFactory> factory;
winrt::com_ptr<IDWriteTextFormat> format;
};

184
src/common/d2d_window.cpp Normal file
View file

@ -0,0 +1,184 @@
#include "pch.h"
#include "d2d_window.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
D2DWindow::D2DWindow() {
static const WCHAR* class_name = L"PToyD2DPopup";
WNDCLASS wc = {};
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
wc.lpszClassName = class_name;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = d2d_window_proc;
RegisterClass(&wc);
hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOREDIRECTIONBITMAP | WS_EX_LAYERED,
wc.lpszClassName,
L"PToyD2DPopup",
WS_POPUP| WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, wc.hInstance, this);
WINRT_VERIFY(hwnd);
}
void D2DWindow::show(UINT x, UINT y, UINT width, UINT height) {
if (!initialized) {
base_init();
}
base_resize(width, height);
render_empty();
on_show();
SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, 0);
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
}
void D2DWindow::hide() {
ShowWindow(hwnd, SW_HIDE);
on_hide();
}
void D2DWindow::initialize() {
base_init();
}
void D2DWindow::base_init() {
std::unique_lock lock(mutex);
// D2D1Factory is independent from the device, no need to recreate it if we need to recreate the device.
if (!d2d_factory) {
#ifdef _DEBUG
D2D1_FACTORY_OPTIONS options = { D2D1_DEBUG_LEVEL_INFORMATION };
#else
D2D1_FACTORY_OPTIONS options = {};
#endif
winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,
__uuidof(d2d_factory),
&options,
d2d_factory.put_void()));
}
// For all other stuff - assing nullptr first to release the object, to reset the com_ptr.
d2d_dc = nullptr;
d2d_device = nullptr;
dxgi_factory = nullptr;
dxgi_device = nullptr;
d3d_device = nullptr;
winrt::check_hresult(D3D11CreateDevice(nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr,
0,
D3D11_SDK_VERSION,
d3d_device.put(),
nullptr,
nullptr));
winrt::check_hresult(d3d_device->QueryInterface(__uuidof(dxgi_device), dxgi_device.put_void()));
winrt::check_hresult(CreateDXGIFactory2(0, __uuidof(dxgi_factory), dxgi_factory.put_void()));
winrt::check_hresult(d2d_factory->CreateDevice(dxgi_device.get(), d2d_device.put()));
winrt::check_hresult(d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, d2d_dc.put()));
init();
initialized = true;
}
void D2DWindow::base_resize(UINT width, UINT height) {
std::unique_lock lock(mutex);
if (!initialized) {
return;
}
window_width = width;
window_height = height;
if (window_width == 0 || window_height == 0) {
return;
}
DXGI_SWAP_CHAIN_DESC1 sc_description = {};
sc_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sc_description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sc_description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
sc_description.BufferCount = 2;
sc_description.SampleDesc.Count = 1;
sc_description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
sc_description.Width = window_width;
sc_description.Height = window_height;
dxgi_swap_chain = nullptr;
winrt::check_hresult(dxgi_factory->CreateSwapChainForComposition(dxgi_device.get(),
&sc_description,
nullptr,
dxgi_swap_chain.put()));
composition_device = nullptr;
winrt::check_hresult(DCompositionCreateDevice(dxgi_device.get(),
__uuidof(composition_device),
composition_device.put_void()));
composition_target = nullptr;
winrt::check_hresult(composition_device->CreateTargetForHwnd(hwnd, true, composition_target.put()));
composition_visual = nullptr;
winrt::check_hresult(composition_device->CreateVisual(composition_visual.put()));
winrt::check_hresult(composition_visual->SetContent(dxgi_swap_chain.get()));
winrt::check_hresult(composition_target->SetRoot(composition_visual.get()));
dxgi_surface = nullptr;
winrt::check_hresult(dxgi_swap_chain->GetBuffer(0, __uuidof(dxgi_surface), dxgi_surface.put_void()));
D2D1_BITMAP_PROPERTIES1 properties = {};
properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
properties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
d2d_bitmap = nullptr;
winrt::check_hresult(d2d_dc->CreateBitmapFromDxgiSurface(dxgi_surface.get(),
properties,
d2d_bitmap.put()));
d2d_dc->SetTarget(d2d_bitmap.get());
resize();
}
void D2DWindow::base_render() {
std::unique_lock lock(mutex);
if (!initialized || !d2d_dc || !d2d_bitmap)
return;
d2d_dc->BeginDraw();
render(d2d_dc.get());
winrt::check_hresult(d2d_dc->EndDraw());
winrt::check_hresult(dxgi_swap_chain->Present(1, 0));
winrt::check_hresult(composition_device->Commit());
}
void D2DWindow::render_empty() {
std::unique_lock lock(mutex);
if (!initialized || !d2d_dc || !d2d_bitmap)
return;
d2d_dc->BeginDraw();
d2d_dc->Clear();
winrt::check_hresult(d2d_dc->EndDraw());
winrt::check_hresult(dxgi_swap_chain->Present(1, 0));
winrt::check_hresult(composition_device->Commit());
}
D2DWindow::~D2DWindow() {
ShowWindow(hwnd, SW_HIDE);
DestroyWindow(hwnd);
}
D2DWindow* D2DWindow::this_from_hwnd(HWND window) {
return reinterpret_cast<D2DWindow*>(GetWindowLongPtr(window, GWLP_USERDATA));
}
LRESULT __stdcall D2DWindow::d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
case WM_NCCREATE: {
auto create_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(create_struct->lpCreateParams));
return TRUE;
}
case WM_MOVE:
case WM_SIZE:
this_from_hwnd(window)->base_resize((unsigned)lparam & 0xFFFF, (unsigned)lparam >> 16);
// Fall through to call 'base_render()'
case WM_PAINT:
this_from_hwnd(window)->base_render();
return 0;
default:
return DefWindowProc(window, message, wparam, lparam);
}
}

60
src/common/d2d_window.h Normal file
View file

@ -0,0 +1,60 @@
#pragma once
#include <winrt/base.h>
#include <Windows.h>
#include <dxgi1_3.h>
#include <d3d11_2.h>
#include <d2d1_3.h>
#include <d2d1_3helper.h>
#include <d2d1helper.h>
#include <dcomp.h>
#include <dwmapi.h>
#include <string>
#include "d2d_svg.h"
class D2DWindow
{
public:
D2DWindow();
void show(UINT x, UINT y, UINT width, UINT height);
void hide();
void initialize();
virtual ~D2DWindow();
protected:
// Implement this:
// Initialization - called when D2D device needs to be created.
// When called all D2DWindow members will be initialized, including d2d_dc
virtual void init() = 0;
// resize - when called, window_width and window_height will have current window size
virtual void resize() = 0;
// render - called on WM_PAIT, BeginPaint/EndPaint is handled by D2DWindow
virtual void render(ID2D1DeviceContext5* d2d_dc) = 0;
// on_show, on_hide - called when the window is about to be shown or about to be hidden
virtual void on_show() = 0;
virtual void on_hide() = 0;
static LRESULT __stdcall d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
static D2DWindow* this_from_hwnd(HWND window);
void base_init();
void base_resize(UINT width, UINT height);
void base_render();
void render_empty();
std::recursive_mutex mutex;
bool initialized = false;
HWND hwnd;
UINT window_width, window_height;
winrt::com_ptr<ID3D11Device> d3d_device;
winrt::com_ptr<IDXGIDevice> dxgi_device;
winrt::com_ptr<IDXGIFactory2> dxgi_factory;
winrt::com_ptr<IDXGISwapChain1> dxgi_swap_chain;
winrt::com_ptr<IDCompositionDevice> composition_device;
winrt::com_ptr<IDCompositionTarget> composition_target;
winrt::com_ptr<IDCompositionVisual> composition_visual;
winrt::com_ptr<IDXGISurface2> dxgi_surface;
winrt::com_ptr<ID2D1Bitmap1> d2d_bitmap;
winrt::com_ptr<ID2D1Factory6> d2d_factory;
winrt::com_ptr<ID2D1Device5> d2d_device;
winrt::com_ptr<ID2D1DeviceContext5> d2d_dc;
};

28
src/common/dpi_aware.cpp Normal file
View file

@ -0,0 +1,28 @@
#include "pch.h"
#include "dpi_aware.h"
#include "monitors.h"
#include <ShellScalingApi.h>
HRESULT DPIAware::GetScreenDPIForWindow(HWND hwnd, UINT &dpi_x, UINT &dpi_y) {
auto monitor_handle = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
dpi_x = 0;
dpi_y = 0;
if (monitor_handle != nullptr) {
return GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
} else {
return E_FAIL;
}
}
void DPIAware::Convert(HMONITOR monitor_handle, int &width, int &height) {
if (monitor_handle == NULL) {
const POINT ptZero = { 0, 0 };
monitor_handle = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
}
UINT dpi_x, dpi_y;
if (GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y) == S_OK) {
width = width * dpi_x / DEFAULT_DPI;
height = height * dpi_y / DEFAULT_DPI;
}
}

11
src/common/dpi_aware.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include "windef.h"
class DPIAware {
private:
static const int DEFAULT_DPI = 96;
public:
static HRESULT GetScreenDPIForWindow(HWND hwnd, UINT & dpi_x, UINT & dpi_y);
static void Convert(HMONITOR monitor_handle, int &width, int &high);
};

67
src/common/monitors.cpp Normal file
View file

@ -0,0 +1,67 @@
#include "pch.h"
#include "monitors.h"
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs) {
auto lhs_tuple = std::make_tuple(lhs.rect.left, lhs.rect.right, lhs.rect.top, lhs.rect.bottom);
auto rhs_tuple = std::make_tuple(rhs.rect.left, rhs.rect.right, rhs.rect.top, rhs.rect.bottom);
return lhs_tuple == rhs_tuple;
}
static BOOL CALLBACK get_displays_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcWork);
return true;
};
static BOOL CALLBACK get_displays_enum_cb_with_toolbar(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
reinterpret_cast<std::vector<MonitorInfo>*>(data)->emplace_back(monitor, monitor_info.rcMonitor);
return true;
};
std::vector<MonitorInfo> MonitorInfo::GetMonitors(bool include_toolbars) {
std::vector<MonitorInfo> monitors;
EnumDisplayMonitors(NULL, NULL, include_toolbars ? get_displays_enum_cb_with_toolbar : get_displays_enum_cb, reinterpret_cast<LPARAM>(&monitors));
std::sort(begin(monitors), end(monitors), [](const MonitorInfo& lhs, const MonitorInfo& rhs) {
return lhs.rect < rhs.rect;
});
return monitors;
}
static BOOL CALLBACK get_primary_display_enum_cb(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
if (monitor_info.dwFlags & MONITORINFOF_PRIMARY) {
reinterpret_cast<MonitorInfo*>(data)->handle = monitor;
reinterpret_cast<MonitorInfo*>(data)->rect = monitor_info.rcWork;
}
return true;
};
MonitorInfo MonitorInfo::GetPrimaryMonitor() {
MonitorInfo primary({}, {});
EnumDisplayMonitors(NULL, NULL, get_primary_display_enum_cb, reinterpret_cast<LPARAM>(&primary));
return primary;
}
MonitorInfo MonitorInfo::GetFromWindow(HWND hwnd) {
auto monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
return GetFromHandle(monitor);
}
MonitorInfo MonitorInfo::GetFromPoint(POINT p) {
auto monitor = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST);
return GetFromHandle(monitor);
}
MonitorInfo MonitorInfo::GetFromHandle(HMONITOR monitor) {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor, &monitor_info);
return MonitorInfo(monitor, monitor_info.rcWork);
}

41
src/common/monitors.h Normal file
View file

@ -0,0 +1,41 @@
#pragma once
#include <Windows.h>
#include <vector>
struct ScreenSize {
explicit ScreenSize(RECT rect) : rect(rect) {}
RECT rect;
int left() const { return rect.left; }
int right() const { return rect.right; }
int top() const { return rect.top; }
int bottom() const { return rect.bottom; }
int height() const { return rect.bottom - rect.top; };
int width() const { return rect.right - rect.left; };
POINT top_left() const { return { rect.left, rect.top }; };
POINT top_middle() const { return { rect.left + width() / 2, rect.top }; };
POINT top_right() const { return { rect.right, rect.top }; };
POINT middle_left() const { return { rect.left, rect.top + height() / 2 }; };
POINT middle() const { return { rect.left + width() / 2, rect.top + height() / 2 }; };
POINT middle_right() const { return { rect.right, rect.top + height() / 2 }; };
POINT bottom_left() const { return { rect.left, rect.bottom }; };
POINT bottm_midle() const { return { rect.left + width() / 2, rect.bottom }; };
POINT bottom_right() const { return { rect.right, rect.bottom }; };
};
struct MonitorInfo : ScreenSize {
explicit MonitorInfo(HMONITOR monitor, RECT rect) : handle(monitor), ScreenSize(rect) {}
HMONITOR handle;
// Returns monitor rects ordered from left to right
static std::vector<MonitorInfo> GetMonitors(bool include_toolbar);
// Return primary display
static MonitorInfo GetPrimaryMonitor();
// Return monitor on which hwnd window is displayed
static MonitorInfo GetFromWindow(HWND hwnd);
// Return monitor nearest to a point
static MonitorInfo GetFromPoint(POINT p);
// Return monitor info given a HMONITOR
static MonitorInfo GetFromHandle(HMONITOR monitor);
};
bool operator==(const ScreenSize& lhs, const ScreenSize& rhs);

1
src/common/pch.cpp Normal file
View file

@ -0,0 +1 @@
#include "pch.h"

26
src/common/pch.h Normal file
View file

@ -0,0 +1,26 @@
#include <winrt/base.h>
#include <Windows.h>
#include <dxgi1_3.h>
#include <d3d11_2.h>
#include <d2d1_3.h>
#include <d2d1_3helper.h>
#include <d2d1helper.h>
#include <dwrite.h>
#include <dcomp.h>
#include <dwmapi.h>
#include <Shobjidl.h>
#include <Shlwapi.h>
#include <string>
#include <algorithm>
#include <chrono>
#include <mutex>
#include <thread>
#include <functional>
#include <condition_variable>
#include <stdexcept>
#include <tuple>
#include <unordered_set>
#include <string>
#include <vector>
#include "common.h"

View file

@ -0,0 +1,75 @@
#include "pch.h"
#include "settings_helpers.h"
#include <filesystem>
#include <fstream>
namespace PTSettingsHelper {
std::wstring get_root_save_folder_location() {
PWSTR local_app_path;
std::wstring result(L"");
winrt::check_hresult(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &local_app_path));
result = std::wstring(local_app_path);
CoTaskMemFree(local_app_path);
result += L"\\Microsoft\\PowerToys";
std::filesystem::path save_path(result);
if (!std::filesystem::exists(save_path)) {
std::filesystem::create_directories(save_path);
}
return result;
}
std::wstring get_module_save_folder_location(const std::wstring& powertoy_name) {
std::wstring result = get_root_save_folder_location();
result += L"\\";
result += powertoy_name;
std::filesystem::path save_path(result);
if (!std::filesystem::exists(save_path)) {
std::filesystem::create_directories(save_path);
}
return result;
}
std::wstring get_module_save_file_location(const std::wstring& powertoy_name) {
std::wstring result = get_module_save_folder_location(powertoy_name);
result += L"\\settings.json";
return result;
}
std::wstring get_powertoys_general_save_file_location() {
std::wstring result = get_root_save_folder_location();
result += L"\\settings.json";
return result;
}
void save_module_settings(const std::wstring& powertoy_name, web::json::value& settings) {
std::wstring save_file_location = get_module_save_file_location(powertoy_name);
std::ofstream save_file(save_file_location, std::ios::binary);
settings.serialize(save_file);
save_file.close();
}
web::json::value load_module_settings(const std::wstring& powertoy_name) {
std::wstring save_file_location = get_module_save_file_location(powertoy_name);
std::ifstream save_file(save_file_location, std::ios::binary);
web::json::value result = web::json::value::parse(save_file);
save_file.close();
return result;
}
void save_general_settings(web::json::value& settings) {
std::wstring save_file_location = get_powertoys_general_save_file_location();
std::ofstream save_file(save_file_location, std::ios::binary);
settings.serialize(save_file);
save_file.close();
}
web::json::value load_general_settings() {
std::wstring save_file_location = get_powertoys_general_save_file_location();
std::ifstream save_file(save_file_location, std::ios::binary);
web::json::value result = web::json::value::parse(save_file);
save_file.close();
return result;
}
}

View file

@ -0,0 +1,13 @@
#pragma once
#include <string>
#include <Shlobj.h>
#include <cpprest/json.h>
namespace PTSettingsHelper {
void save_module_settings(const std::wstring& powertoy_name, web::json::value& settings);
web::json::value load_module_settings(const std::wstring& powertoy_name);
void save_general_settings(web::json::value& settings);
web::json::value load_general_settings();
}

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