Compare commits

..

65 Commits

Author SHA1 Message Date
yuyoyuppe
221df3d26d Fix lack of tray icon #268 by handling initial Shell_NotifyIcon failure (#789)
* Fix lack of tray icon #268 by handling initial Shell_NotifyIcon failure
2019-11-27 17:19:10 +03:00
yuyoyuppe
40db3a5d7d Wix installer: kill explorer if shellext is detected (#790) 2019-11-27 16:53:18 +03:00
Bartosz Sosnowski
ee1a1fd614 Prevent number being swallow while dragging. (#788) 2019-11-27 10:32:09 +01:00
Chris Davis
8e8be502fd Handle DPI change gracefully (#786)
* Ensure icon in context menu is not leaked

* Hande theme/dpi size change gracefully
2019-11-26 19:45:18 -08:00
Bartosz Sosnowski
ae4413d0aa Improve key code to key name mapping. (#784)
Use the key detected by WebUI and our mapping only for from_settings call.
Replace the old Win + ~ with the correct value
2019-11-26 16:14:34 +01:00
Enrico Giordani
51b791f9c0 Version 0.14.0 (#782) 2019-11-26 11:46:22 +01:00
Mike Harsh
767c3c942b Update README.md 2019-11-25 06:11:34 -08:00
Mike Harsh
3fcace6660 December update with info on 0.14, 0.15 and 0.16 2019-11-25 06:10:44 -08:00
Mike Harsh
4c600f5748 Updated shortcut key information 2019-11-25 06:06:29 -08:00
Bartosz Sosnowski
d84342733d Prevent ShortcutGuide from crashing when it is being disabled while shown. 2019-11-25 15:06:06 +01:00
Bartosz Sosnowski
d6f0f9ec0e FancyZones settings: show proper hotkey even when wrong key was saved before
This makes the Hotkey settings object ignore the key value stored in
json. Instead it will be deduced from the current keyboard layout and
the vk_code.
2019-11-25 11:54:10 +01:00
Bartosz Sosnowski
fbc922fe97 Add some margins to settings icons 2019-11-22 16:19:36 +01:00
Enrico Giordani
4be84e035f revert overrideSnapHotkeys logic after regression (#756) 2019-11-22 10:56:11 +01:00
Bartosz Sosnowski
254474d12d Make the hotkey control display correct key
Credit to @doterik for the idea in https://github.com/microsoft/PowerToys/issues/700#issuecomment-554329895

RApplies to https://github.com/microsoft/PowerToys/issues/700
2019-11-20 10:00:53 +01:00
Bartosz Sosnowski
5615987ea2 Make some settings descriptions wrap correctly
Applies to https://github.com/microsoft/PowerToys/issues/712
2019-11-20 10:00:53 +01:00
Bartosz Sosnowski
3a93246f08 More padding after PowerToy description
Applies to https://github.com/microsoft/PowerToys/issues/716
2019-11-20 10:00:53 +01:00
Bartosz Sosnowski
633784fae2 Use dynamic version in settings
Applies to https://github.com/microsoft/PowerToys/issues/736
2019-11-20 10:00:53 +01:00
Bret
af127468a6 Merge pull request #739 from TheMrJukes/master
FancyZones: Remove legacy editor
2019-11-19 10:00:49 -08:00
Clint Rutkas
f892c1284b Merge pull request #740 from docs-product/patch-1
Update README.md
2019-11-18 23:35:54 -08:00
docs
d762b5a017 Update README.md 2019-11-18 18:16:46 -08:00
Bret
28d7835327 User/bretan/fz remove legacy editor (#1)
* Removed and runs
Still needs some extra cleanup and addressing open issues

* Removed and runs
Still needs some extra cleanup and addressing open issues

* Clean

* Update
2019-11-18 15:29:42 -08:00
Bartosz Sosnowski
03438f9192 FancyZones: improve windows and apps filtering (#673)
Unifies the way windows are considered "interesting" by FancyZone.
Berfore the change WinKey + arrows would use different method than
dragging. This PR makes both use the WinKey + arrows method.

Cleans up FancyZones Settings.cpp by removing m_configStrings variable.
Contrary to its name it was used to create color picker control.

Adds a multiline option to the text input to settings. Uses this to
provide the user with a way to exclude certain apps from snapping to
zones.
2019-11-18 10:29:56 +01:00
Clint Rutkas
4df1d2093f Merge pull request #323 from casungo/master
Added Hi-res logo (4k PNG)
2019-11-15 15:28:18 -08:00
casungo
62a019cc5d Moved png to doc/images 2019-11-15 23:41:05 +01:00
casungo
36c78e9686 Delete Logo-HiRes.png 2019-11-15 23:36:36 +01:00
yuyoyuppe
cb13cfdda7 FancyZonesEditor: open a tab with the selected layout on startup (#715) 2019-11-15 10:40:10 +03:00
Clint Rutkas
0082f56b58 Update README.md 2019-11-13 15:45:59 -08:00
Chris Davis
b490a72c1d Ensure icon in context menu is not leaked (#709) 2019-11-13 14:13:14 -08:00
Chris Davis
3c0b479669 Merge pull request #697 from chrdavis/master
Update to PowerRename
2019-11-12 14:16:10 -08:00
Chris Davis
c9ad09226b Remove call to save_to_settings_file 2019-11-12 13:56:12 -08:00
yuyoyuppe
4e771ecfb7 initialize all OnThreadExecutor fields and clarify intent further (#701) 2019-11-12 18:29:54 +03:00
vldmr11080
be86cd4028 Customize system menu items through dedicated API (#677)
Document new interface changes.
2019-11-12 11:48:14 +01:00
Chris Davis
3ddbe92f37 Fix incorrect setting type in set_config handler 2019-11-11 23:28:31 -08:00
Chris Davis
ca67ea9b4c Merge pull request #2 from microsoft/master
PR from upstream
2019-11-11 23:03:31 -08:00
Clint Rutkas
9f78af29bf Merge pull request #694 from crutkas/master
adding in specs
2019-11-11 21:55:40 -08:00
Clint Rutkas
6821a05f76 Update Gif-Maker.md 2019-11-11 21:54:54 -08:00
Chris Davis
e328c5d505 * Fix crashing bug in event vector cleanup
* Fix warnings in settings.cpp
* Add settings to ui of powertoys
2019-11-11 20:58:39 -08:00
Clint Rutkas
f814d26a4a change of filename 2019-11-11 13:59:03 -08:00
Clint Rutkas
3fc06e6f4f Adding in specs from GH and from MIke's repo 2019-11-11 13:57:46 -08:00
Clint Rutkas
d876c267d6 Merge pull request #692 from microsoft/Readme-adjustment
Updates for readme
2019-11-11 13:16:29 -08:00
Clint Rutkas
1268a463ac Merge branch 'master' of https://github.com/microsoft/PowerToys 2019-11-11 12:46:06 -08:00
Clint Rutkas
e64d75a297 Revert "Work for .12 release. adjusted formatting a bit too"
This reverts commit cd9208b541.
2019-11-11 12:45:51 -08:00
Clint Rutkas
7900edc96c Merge pull request #691 from enricogior/remove-icons-from-root
Remove images from the root
2019-11-11 12:16:32 -08:00
Clint Rutkas
692421ee13 Updates for readme
- added in processor support type with issue links
- added in section to call out WinStore support issue
- reduced size on image
2019-11-11 11:57:10 -08:00
Chris Davis
1e89054897 * Ensure rename dialog is centered
* Ensure children are renamed before parent items
* Add settings handler
* Replace old text referencing smart rename with power rename
2019-11-11 11:00:42 -08:00
Enrico Giordani
ae1112ae11 Remove images from the root
the images are already available (and used) in doc/images/
2019-11-11 17:03:32 +01:00
Chris Davis
800984489d Merge pull request #679 from chrdavis/master
Small bugs fixes to PowerRename
2019-11-09 00:31:34 -08:00
Chris Davis
997ea3a2f5 A couple minor bug fixes 2019-11-09 00:30:00 -08:00
Chris Davis
b9b60a1346 Merge pull request #1 from microsoft/master
Sync with master
2019-11-08 12:05:57 -08:00
yuyoyuppe
e8edbd5394 clear FancyZones::m_zoneWindowMap on Destroy, since it stores 'this', causing a leak (#664) 2019-11-07 22:05:12 +03:00
yuyoyuppe
f3e25ae3e6 Fix for different per-monitor scaling (#657)
* Use DPIAware::DEFAULT_DPI

* Make runner DPI-unaware, since it doesn't need to use a Per Monitor V2 DPI.

* Programmatically enable "Per Monitor V2 DPI" for the runner proccess and use a separate DPI-unaware thread for the corresponding API calls

* Increase PCH memory limit for settings project

* Address review issues

* Draw zoneWindows properly scaled
2019-11-07 21:56:32 +03:00
yuyoyuppe
a9518c2e55 Wrap around colorIndex in a colors array (#669) 2019-11-07 17:50:04 +01:00
yuyoyuppe
c4fc67301c Add switch to turn off keyboard hooks while debugging, since they could mess system-wide input 2019-11-07 09:52:34 +01:00
Enrico Giordani
39cbc59c12 Don't auto close issues referenced in PR (#663)
Remove space in checkboxes
2019-11-06 10:37:42 +01:00
Bartosz Sosnowski
96aa6ae3ef Fix Chrome tab move leaving zone highlighted (#656)
Fixes: https://github.com/microsoft/PowerToys/issues/534
2019-11-05 14:29:42 +01:00
Mike Harsh
94d07833c5 Removed the batch renamer now that PowerRename is released 2019-11-04 09:42:29 -08:00
Chris Davis
1d3acbe40b Merge pull request #655 from chrdavis/master
Switch to modeless experience and resize list view columns on dialog size
2019-11-03 22:24:39 -08:00
Chris Davis
389590e45d Ensure columns are resized when the dialog is resized. Also switch to a modeless experience instead of modal for the dialog. We no longer disable the parent window. 2019-11-03 22:22:35 -08:00
Chris Davis
ea3cb026c7 Merge pull request #647 from chrdavis/master
Fix single regex search replace bug
2019-11-01 23:57:22 -07:00
Chris Davis
1efe5bff9f Fix single regex search replace
Fix an issue where regular expression search and replace was not being done correctly when MatchAllOccurences is not specified.
2019-11-01 23:56:29 -07:00
Chris Davis
df4fa549ef Allow resizing of PowerRename dialog (#635) 2019-11-01 08:54:49 -07:00
Chris Davis
cc7a706f52 Fix painting issue with buttons after resize 2019-11-01 08:52:54 -07:00
Chris Davis
d4256dad30 Allow resizing of PowerRename dialog 2019-10-31 23:57:42 -07:00
Clint Rutkas
cd9208b541 Work for .12 release. adjusted formatting a bit too 2019-10-29 04:08:11 -07:00
casungo
38029efe50 Added Hi-res logo (4k PNG) 2019-09-09 16:58:37 +02:00
102 changed files with 3502 additions and 2438 deletions

View File

@@ -6,11 +6,11 @@
<!-- 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
* [] Applies to #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

BIN
Logo.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -23,6 +23,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "interface", "interface", "{
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\powertoy_system_menu.h = src\modules\interface\powertoy_system_menu.h
src\modules\interface\win_hook_event_data.h = src\modules\interface\win_hook_event_data.h
EndProjectSection
EndProject

View File

@@ -1,22 +1,32 @@
# Overview
PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity.
<img align="right" width="200" src="./doc/images/Logo.jpg">
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/).
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/).
![logo](doc/images/Logo.jpg)
## Build Status
[![Build Status](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=master)](https://dev.azure.com/ms/PowerToys/_build?definitionId=35096)
## Installation
_(Note: in order to run PowerToys, you'll need to be running at least Windows build 17134 or higher. Also, PowerToys does not currently support Windows ARM machines)_
_**Note:** in order to run PowerToys, you'll need to be running at least Windows build 17134 or higher._
The latest release of PowerToys can be downloaded currently a few different ways. Our current recommended way is via GitHub.
| x64 | x86 | ARM |
|:---:|:---:|:---:|
| Supported | [Issue #602](https://github.com/microsoft/PowerToys/issues/602) | [Issue #490](https://github.com/microsoft/PowerToys/issues/490)|
### GitHub
The preview of these utilities can be installed from the [PowerToys GitHub releases page](https://github.com/Microsoft/powertoys/releases). 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`.
### Windows Store
On backlog, [Issue #413](https://github.com/microsoft/PowerToys/issues/413)
### Chocolatey (Unofficial)
Download and upgrade PowerToys from [Chocolatey](https://chocolatey.org).
@@ -35,10 +45,6 @@ choco upgrade powertoys
If you have any issues when installing/upgrading the package please go to the [package page](https://chocolatey.org/packages/powertoys) and follow the [Chocolatey triage process](https://chocolatey.org/docs/package-triage-process)
## Build Status
[![Build Status](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=master)](https://dev.azure.com/ms/PowerToys/_build?definitionId=35096)
## PowerToy Utilities
### FancyZones
@@ -55,11 +61,13 @@ If you have any issues when installing/upgrading the package please go to the [p
Chris Davis contributed his [SmartRename tool](https://github.com/chrdavis/SmartRename) into PowerToys!
![SmartRename](https://github.com/microsoft/PowerToys/raw/master/src/modules/powerrename/images/PowerRenameDemo.gif)
### 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)
* [Animated gif screen recorder](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/GIF%20Maker%20Spec.md)
* [Process terminate tool](doc/specs/Terminate%20Spec.md)
* [Animated gif screen recorder](doc/specs/Gif-Maker.md)
### Backlog
@@ -67,11 +75,9 @@ The full backlog of utilities can be found [here](https://github.com/Microsoft/P
## What's Happening
### October Update
### December Update
**Update** - We've shipped 0.12! This release includes bug fixes, addresses issues and implements many feature suggestions. This build and installer is also signed by Microsoft. Last, but not least, this release includes a new utility: Chris Davis has integrated [SmartRename tool](https://github.com/chrdavis/SmartRename) into PowerToys!
![SmartRename](https://github.com/microsoft/PowerToys/raw/master/src/modules/powerrename/images/PowerRenameDemo.gif)
We're planning to ship 0.14 before December with a handful of key bug fixes from the community. After that 0.15 will bring .msix installer support and deployment and automatic updates from the Windows Store and 0.16 will add support for X86 and ARM64 processors (including the Surface Pro X).
## Developer Guidance

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

BIN
doc/images/Logo-HiRes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -6,7 +6,6 @@ The list below is the set of utilities we're considering and the rough priority
* 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

108
doc/specs/Gif-Maker.md Normal file
View File

@@ -0,0 +1,108 @@
# GIF Maker Spec
![Terminate](../images/Logo.jpg "Power Toys")
- **What is it:** Users can record their screen and turn the recording into a GIF.
- **Authors:** Benjamin Leverette and Prudence Phillips
- **Spec Status:** Draft
## 1. Overview
### 1.1. Elevator Pitch / Narrative
David loves using GIFs to add creativity to his typical responses to messages. His friend Amanda emails him and asks what he would like to eat for lunch today. David recently watched a burrito video, so he uses the GIF maker to screen record a brief moment from the video in order to tell Amanda that it's "Burrito Day."
### 1.2. Customers
Like all utilities from PowerToys, the GIF Maker feature is for power users and developers who are looking to tune and streamline their Windows experience for greater productivity.
### 1.3. Problem Statement and Supporting Customer Insights
Power users need a way to better record their screens and use the recordings to create GIFs. A teammate held a personal interactions with the community that validate the usefulness of a feature that provides such functionality.
### 1.4. Existing Solutions or Expectations
Users currently must use the game bar in order to record the screen, and there is no way to turn recordins into GIFs. There are third-party resources that allow users to create GIFs online after uploading images and videos.
### 1.5. Goals/Non-Goals
Design and develop a feature that can record screens and turn them into GIFs within an 8 week period.
## 2. Definition of Success
### 2.1. Expected Impact: Customer, and Technology Outcomes, Experiments + Measures
This feature will give users the ability to screen record and create GIFs effectively and add a new dimension to using GIFs on Windows. Measures of success include:
- A score of an average of 3.75 stars on a new Consumer Design Satisfaction Survey
- 5% increase in number of stars on the Github repo within first month of release
- Installed by 10% of users who have starred the PowerToys Github
- Uninstalled by less than 30% of users who installed
- Launched by over 60% of users who installed
## 3. Requirements
### 3.1. Functional Requirements
#### 3.1.1. Initial UX/UI
Users may or may not have any open windows on their screen. They can access this utility the same way you would access the Snip & Sketch tool on Windows or using an assigned keyboard shortcut. After the tool has been accessed by the user they can:
- Start a new screen recording
- The tool will record the user's entire screen
- Video can be saved in multiple formats (.GIF, .MP4, .HEIC, .M4A, etc...)
- Edit an already existing video into a GIF
- Keyboard Shortcut Suggestions:
- Ctrl + Alt + R
- Ctrl + Alt + G
![GIF Maker UI](images/GIF%20Maker%20Spec.png "GIF Maker UI")
#### 3.1.2. File Button Features
Upon opening the GIF Maker utility, users must click 'New' to begin. They will have two options: 'Record' and 'Open'.
- Record
- Choosing this option closes the GIF Maker window and displays a record button.
- When they click the record button, it starts a brief countdown. Once the countdown concludes, it records the user's entire screen.
- User clicks the stop button to end the recording
- Open
- If the user clicks 'Open', the mini File Explorer window opens for the user to select a video.
- Once a video is selected, it appears in the GIF Maker, below the tool bar, for the user to edit.
- Saving
- Recorded videos can be saved in multiple video formats
- Users can further edit their videos and save them as GIFs
#### 3.1.3. GIF Editing Tools
- Add Text
- Users can add text to their videos
- Default Windows fonts will be available
- Crop Video
- Users can crop their videos manually or use the default cropping options. The default options will include:
- 1:1
- 4:3
- 3:2
- 16:9
- Users can also leave their video in their original dimensions
- Trim Video
- Users can trim the length of their videos
- Users can make GIFs with a minimum time of 0.05 seconds and a maximum time of 6.00 seconds
#### 3.1.4. Settings
The PowerToys app will have a settings framework for the GIF Maker utility to plug into. The settings framework has a UI frame that creates a page for the utility. Its settings will be represented as a json blob with the following features:
### 3.2. Enable/Disable
- The user can select to enable or disable the GIF Maker utility's functionality, which initializes or suspends its resource use.
### 3.3. Custom Configuration
- Similar to the functionality of a switch or radio button, the user will be able to select options for the countdown: 0, 5, or 10 secs.
## 4. Dependencies
- Explore Internship Program limits us to an 8-week window to complete the task.
- Availability of public API's

60
doc/specs/PowerRename.md Normal file
View File

@@ -0,0 +1,60 @@
# PowerRename File Classification Spec
![Power Rename](../images/Logo.jpg "Power Toys")
- **What is it:** Users can quickly rename and group files.
- **Authors:** Benjamin Leverette and Prudence Phillips
- **Spec Status:** Draft
## 1. Overview
### 1.1. Elevator Pitch / Narrative
David has recently uploaded thousands of pictures from his camera to his Surface Laptop. Unfortunately, the images all have generic names such as 'IMG_141' instead of labels that he can identify. David downloads the File Classification PowerToy that allows him to create new folders with files that share a label, rename a group of files with a label, or change the name or portion of a name in a group of files to another name.
### 1.2. Customers
Like all utilities from PowerToys, the File Classification feature is for power users and developers who are looking to tune and streamline their Windows experience for greater productivity.
### 1.3. Problem Statement and Supporting Customer Insights
Power users need a better way to organize files, from renaming files to creating new folders for similar files. Our PowerToys Consumer Survey received feedback validating the usefulness of a feature that provides such functionality.
### 1.4. Existing Solutions or Expectations
Users currently have to highlight a group of files and right click to rename them. Users must manually create a folder, move files to that folder, and rename them. There are third-party resources that allow users to rename files similarly.
We expect users to install and enable PowerToys for Windows in order to access the File Classification utility.
### 1.5. Goals/Non-Goals
Design and develop a feature that can rename and group files within an 8 week period.
## 2. Definition of Success
### 2.1. Expected Impact: Customer, and Technology Outcomes, Experiments + Measures
Our PowerToys Consumer Survey received an abundant amount of participation and feedback from a community of passionate power users. This feature will give them the ability to rename, group and organize files in a way that makes their virtual library of files more organized and efficient. As interns, we would have 8 weeks to complete the project.
## 3. Requirements
### 3.1. Functional Requirements
- Users must select a group of files by checking each file or using Shift + directional keys. They must then use a shortcut to open the File Classification utility, which provides three options:
- Automates folder creation and movement of user-selected files after receiving a label determined by the user.
- Renames all user-selected files after receiving a label determined by the user.
- Identifies a string of characters in the names of user-selected files and changes it to a string determined by the user.
- Labels are used to rename files by completely overwriting the files' current names with the custom 'Label' typed by the user and each file receives a counting number.
- Shortcut should take accessibility into account.
- Perhaps Windows key + C?
![Rename](images/File%20Classification%20Design%20Blurred.png "Rename")
### 3.2. Measure Requirements
- Survey what power users want out of the File Classification feature through forms and Github.
## 4. Dependencies
- Explore Internship Program limits us to an 8-week window to complete the task.
- Availability of public API's

View File

@@ -0,0 +1,89 @@
# **Terminate Program Spec**
![Terminate](../images/Logo.jpg "Power Toys")
- **What is it:** Shortcut for users to quickly terminate a running program
- **Authors:** Benjamin Leverette and Prudence Phillips
- **Spec Status:** Draft
## 1. Overview
### 1.1. Elevator Pitch / Narrative
Mike is debugging his code in Visual Studio and the program freezes with the "App not responding" text displaying on the title bar, informing him that he cannot continue his work without closing the program and restarting it. Mike has tried to close the program using the close button and end task via the task manager, but none of these mechanisms work in helping him terminate the process so he can proceed with his work. With this PowerToy installed, Mike now has a visual and accessible last-resort method to help him kill the process.
### 1.2. Customers
PowerToys is mainly targeted towards Windows Power Users though it is available to users who want to experience using windows in a more efficient and productive way.
### 1.3. Problem Statement and Supporting Customer Insights
Windows users need an accessible mechanism to completely kill a process when it is being unresponsive and hindering work flow. The team is still required to find solutions for:
- A public name for this PowerToy.
- The degree to which the process will be terminated.
### 1.4. Existing Solutions or Expectations
The current methods a user can close a running program in Windows include:
- Clicking on the close button in the program
- Closing the program via task manager
- Using the keyboard shortcut Alt + F4 to close the program
### 1.5. Goals/Non-Goals
- Develop this PowerToy and have sufficient time for testing and integration within our assigned 8 weeks for the project.
- Meet customers expectation with end result of project.
## 2. Definition of Success
### 2.1. Expected Impact: Customer, and Technology Outcomes, Experiments + Measures
The PowerToys repo currently has 200+ people watching, over 4000 stars and 109 forks on github despite having an empty repo. Also, this particular PowerToy received a rating of 3.44/5 in the survey we sent out to the community asking them to rate how useful they think it will be. after the release of this PowerToy, the following will be used to measure our success rate:
- At least a 5% increase in Github stars within a month of release
- A 3.75/5 rating on a post-completion Consumer Satisfaction Survey on this PowerToy.
- 100 downloads & installs within the first month of release.
- Less than 40% of unistalls by users who install this PowerToy
## 3. Requirements
### 3.1. Functional Requirements
To use this PowerToy, a user will:
- Press the chosen keyboard shortcut. This will display the 'Terminate' window.
- Click the left mouse button anywhere in the Terminate Window and drag the cursor to whatever other window they wish to kill.
- Note: users can configure in their options to disable the yes/no prompt and just terminate apps instantly.
- Release the left mouse button over the new app to kill it.
- Once they are done with the utility, user closes the terminate window to exit.
![Terminate](images/Terminate%20Blurred.png "Terminate")
- Keyboard shortcut
- Alt + Shift + X
3.1.1 Settings
The PowerToys app will have a settings framework for the Terminate utility to plug into. The settings framework has a UI frame that creates a page for the utility. Its settings will be represented as a json blob with the following features:
- Enable/Disable
- The user can select to enable or disable the Terminate utility's functionality, which initializes or suspends its resource use.
- Custom Configuration
- Similar to the functionality of a switch or radio button, the user will be able to select options for the appearance of the mouse cursor.
### 3.2 Public Name
The initially proposed name for this app is Terminate App. However, there are multiple other alternative names that we are also considering:
- Destroy App
- Knockdown Program
- Dismantle App
## 4. Dependencies
- The 8 week time limit of the explore internship
- Availability of public APIs, since we intend to make this project open source.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 KiB

19
doc/specs/readme.md Normal file
View File

@@ -0,0 +1,19 @@
# Specs
This folder is where specs for PowerToys will be stored.
## Planning
- [Terminate](Terminate%20Spec.md)
- [GIF Maker](Gif-Maker.md)
## System knowledge
- [PowerToys Settings](PowerToys-fancyzones.md)
- [PowerToys shared hooks](Shared-hooks.md)
## Done
- [FancyZones](PowerToys-fancyzones.md)
- [PowerRename](PowerRename.md)
- Windows key shortcut guide

View File

@@ -7,7 +7,7 @@
<Product Id="*"
Name="PowerToys"
Language="1033"
Version="0.13.0"
Version="0.14.0"
Manufacturer="Microsoft"
UpgradeCode="42B84BF7-5FBF-473B-9C8B-049DC16F7708">
@@ -62,6 +62,10 @@
<Property Id="WixShellExecTarget" Value="[#PowerToys.exe]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<Property Id ="EXISTINGPOWERRENAMEEXTPATH">
<RegistrySearch Id="ExistingExtPath" Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}\InprocServer32" Type="raw"/>
</Property>
<InstallExecuteSequence>
<Custom Action="SetRegisterPowerToysSchTaskParam" Before="RegisterPowerToysSchTask" />
<Custom Action="RegisterPowerToysSchTask" After="InstallFiles">
@@ -156,6 +160,10 @@
<!-- Close 'PowerToys.exe' before uninstall-->
<Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
<!-- Restart explorer.exe if we detect existing powerrenameext.dll installation -->
<util:CloseApplication Target="explorer.exe" RebootPrompt="no" TerminateProcess="0">
EXISTINGPOWERRENAMEEXTPATH
</util:CloseApplication>
<util:CloseApplication CloseMessage="yes" Target="PowerToys.exe" ElevatedCloseMessage="yes" RebootPrompt="no" TerminateProcess="0" />
</Product>

View File

@@ -1,5 +1,6 @@
#include "pch.h"
#include "common.h"
#include "hwnd_data_cache.h"
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#include <strsafe.h>
@@ -32,48 +33,13 @@ std::optional<POINT> get_mouse_pos() {
return point;
}
}
HWND get_filtered_active_window() {
static auto desktop = GetDesktopWindow();
static auto shell = GetShellWindow();
static HWND searchui = nullptr;
auto active_window = GetForegroundWindow();
active_window = GetAncestor(active_window, GA_ROOT);
if (active_window == desktop || active_window == shell || active_window == searchui) {
return nullptr;
}
auto window_styles = GetWindowLong(active_window, GWL_STYLE);
if ((window_styles & WS_CHILD) || (window_styles & WS_DISABLED)) {
return nullptr;
}
window_styles = GetWindowLong(active_window, GWL_EXSTYLE);
if ((window_styles & WS_EX_TOOLWINDOW) ||(window_styles & WS_EX_NOACTIVATE)) {
return nullptr;
}
char class_name[256] = "";
GetClassNameA(active_window, class_name, 256);
if (strcmp(class_name, "SysListView32") == 0 ||
strcmp(class_name, "WorkerW") == 0 ||
strcmp(class_name, "Shell_TrayWnd") == 0 ||
strcmp(class_name, "Shell_SecondaryTrayWnd") == 0 ||
strcmp(class_name, "Progman") == 0) {
return nullptr;
}
if (strcmp(class_name, "Windows.UI.Core.CoreWindow") == 0) {
const static std::wstring cortana_app = L"SearchUI.exe";
auto process_path = get_process_path(active_window);
if (process_path.length() >= cortana_app.length() &&
process_path.compare(process_path.length() - cortana_app.length(), cortana_app.length(), cortana_app) == 0) {
// cache the cortana HWND
searchui = active_window;
return nullptr;
}
}
return active_window;
WindowAndProcPath get_filtered_base_window_and_path(HWND window) {
return hwnd_cache.get_window_and_path(window);
}
HWND get_filtered_active_window() {
return hwnd_cache.get_window(GetForegroundWindow());
}
int width(const RECT& rect) {

View File

@@ -11,6 +11,12 @@ std::optional<RECT> get_window_pos(HWND hwnd);
std::optional<POINT> get_mouse_pos();
// Gets active window, filtering out all "non standard" windows like the taskbar, etc.
HWND get_filtered_active_window();
// Gets window ancestor (usualy the window we want to do stuff with), filtering out all "non standard" windows like the taskbar, etc. and provide the app process path
struct WindowAndProcPath {
HWND hwnd = nullptr;
std::wstring process_path;
};
WindowAndProcPath get_filtered_base_window_and_path(HWND window);
// Calculate sizes
int width(const RECT& rect);

View File

@@ -1,139 +1,143 @@
<?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="version.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>
<?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="hwnd_data_cache.h" />
<ClInclude Include="monitors.h" />
<ClInclude Include="on_thread_executor.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="version.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="hwnd_data_cache.cpp" />
<ClCompile Include="monitors.cpp" />
<ClCompile Include="on_thread_executor.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

@@ -1,112 +1,124 @@
<?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>
<ClInclude Include="version.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>
<?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>
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="on_thread_executor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hwnd_data_cache.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>
<ClCompile Include="on_thread_executor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hwnd_data_cache.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -37,4 +37,8 @@ void DPIAware::Convert(HMONITOR monitor_handle, int &width, int &height) {
width = width * dpi_x / DEFAULT_DPI;
height = height * dpi_y / DEFAULT_DPI;
}
}
}
void DPIAware::EnableDPIAwarenessForThisProcess() {
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}

View File

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

View File

@@ -0,0 +1,120 @@
#include "pch.h"
#include "hwnd_data_cache.h"
HWNDDataCache hwnd_cache;
WindowAndProcPath HWNDDataCache::get_window_and_path(HWND hwnd) {
std::unique_lock lock(mutex);
auto ptr = get_internal(hwnd);
return ptr ? *ptr : WindowAndProcPath{};
}
HWND HWNDDataCache::get_window(HWND hwnd) {
std::unique_lock lock(mutex);
auto ptr = get_internal(hwnd);
return ptr ? ptr->hwnd : nullptr;
}
WindowAndProcPath* HWNDDataCache::get_internal(HWND hwnd) {
auto root = GetAncestor(hwnd, GA_ROOT);
// Filter the fast and easy cases
if (is_invalid_hwnd(root) ||
is_invalid_class(root) ||
is_invalid_style(root)) {
return nullptr;
}
// Get the HWND process path from the cache
DWORD pid = GetWindowThreadProcessId(root, nullptr);
auto cache_ptr = get_from_cache(root, pid);
if (cache_ptr == nullptr) {
cache_ptr = put_in_cache(root, pid);
}
// If the app is a UWP app, check if it isnt banned
if (is_uwp_app(root) && is_invalid_uwp_app(cache_ptr->process_path)) {
// cache the HWND of the invalid app so we wont search for it again
invalid_hwnds.push_back(root);
return nullptr;
}
return cache_ptr;
}
WindowAndProcPath* HWNDDataCache::get_from_cache(HWND root, DWORD pid) {
auto next = next_timestamp();
auto it = std::find_if(begin(cache), end(cache), [&](const auto& entry) {
return root == entry.data.hwnd && pid == entry.pid;
});
if (it != end(cache)) {
it->atime = next;
return &(it->data);
}
else {
return nullptr;
}
}
WindowAndProcPath* HWNDDataCache::put_in_cache(HWND root, DWORD pid) {
auto next = next_timestamp();
auto it = std::min_element(begin(cache), end(cache), [](const auto& lhs, const auto& rhs) {
return lhs.atime < rhs.atime;
});
it->atime = next;
it->pid = pid;
it->data.hwnd = root;
it->data.process_path = get_process_path(root);
return &(it->data);
}
bool HWNDDataCache::is_invalid_hwnd(HWND hwnd) const {
return std::find(begin(invalid_hwnds), end(invalid_hwnds), hwnd) != end(invalid_hwnds);
}
bool HWNDDataCache::is_invalid_class(HWND hwnd) const {
std::array<char, 256> class_name;
GetClassNameA(hwnd, class_name.data(), static_cast<int>(class_name.size()));
for (auto invalid : invalid_classes) {
if (strcmp(invalid, class_name.data()) == 0)
return true;
}
return false;
}
bool HWNDDataCache::is_invalid_style(HWND hwnd) const {
auto style = GetWindowLong(hwnd, GWL_STYLE);
for (auto invalid : invalid_basic_styles) {
if ((invalid & style) != 0) {
return true;
}
}
style = GetWindowLong(hwnd, GWL_EXSTYLE);
for (auto invalid : invalid_ext_styles) {
if ((invalid & style) != 0) {
return true;
}
}
return false;
}
bool HWNDDataCache::is_uwp_app(HWND hwnd) const {
std::array<char, 256> class_name;
GetClassNameA(hwnd, class_name.data(), static_cast<int>(class_name.size()));
return strcmp(class_name.data(), "Windows.UI.Core.CoreWindow") == 0;
}
bool HWNDDataCache::is_invalid_uwp_app(const std::wstring& process_path) const {
for (const auto& invalid : invalid_uwp_apps) {
// check if process_path ends in "invalid"
if (process_path.length() >= invalid.length() &&
process_path.compare(process_path.length() - invalid.length(), invalid.length(), invalid) == 0) {
return true;
}
}
return false;
}
unsigned HWNDDataCache::next_timestamp() {
auto next = ++current_timestamp;
if (next == 0) {
// Handle overflow by invalidating the cache
for (auto& entry : cache) {
entry.data.hwnd = nullptr;
}
}
return next;
}

View File

@@ -0,0 +1,53 @@
#pragma once
#include <vector>
#include <string>
#include <Windows.h>
class HWNDDataCache {
public:
WindowAndProcPath get_window_and_path(HWND hwnd);
HWND get_window(HWND hwnd);
private:
// Return pointer to our internal cache - we cannot pass this to user
// since next call to get_* might invalidate that pointer
WindowAndProcPath* get_internal(HWND hwnd);
WindowAndProcPath* get_from_cache(HWND root, DWORD pid);
WindowAndProcPath* put_in_cache(HWND root, DWORD pid);
// Various validation routines
bool is_invalid_hwnd(HWND hwnd) const;
bool is_invalid_class(HWND hwnd) const;
bool is_invalid_style(HWND hwnd) const;
bool is_uwp_app(HWND hwnd) const;
bool is_invalid_uwp_app(const std::wstring& binary_path) const;
// List of HWNDs that are not interesting - like desktop, cortana, etc
std::vector<HWND> invalid_hwnds = { GetDesktopWindow(), GetShellWindow() };
// List of invalid window basic styles
std::vector<LONG> invalid_basic_styles = { WS_CHILD, WS_DISABLED };
// List of invalid window extended styles
std::vector<LONG> invalid_ext_styles = { WS_EX_TOOLWINDOW, WS_EX_NOACTIVATE };
// List of invalid window classes - things like start menu, etc.
std::vector<const char*> invalid_classes = { "SysListView32", "WorkerW", "Shell_TrayWnd", "Shell_SecondaryTrayWnd", "Progman" };
// List of invalid persistent UWP app - like Cortana
std::vector<std::wstring> invalid_uwp_apps = { L"SearchUI.exe" };
// Cache for HWND/PID pair to process path. A collision here, where a new process
// not in cache gets to reuse a cached PID and then reuses the same HWND handle
// seems unlikely.
std::mutex mutex;
// Handle timestamp wrap
unsigned next_timestamp();
unsigned current_timestamp = 0;
struct Entry {
DWORD pid = 0;
// access time - when retiring element from cache we pick
// one with minimal atime value. We update this value
// every time we query the cache
unsigned atime = 0;
WindowAndProcPath data;
};
std::vector<Entry> cache{ 32 };
};
extern HWNDDataCache hwnd_cache;

View File

@@ -0,0 +1,39 @@
#include "pch.h"
#include "on_thread_executor.h"
OnThreadExecutor::OnThreadExecutor()
: _shutdown_request{false}
, _worker_thread{[this] { worker_thread(); }}
{}
std::future<void> OnThreadExecutor::submit(task_t task) {
auto future = task.get_future();
std::lock_guard lock{_task_mutex};
_task_queue.emplace(std::move(task));
_task_cv.notify_one();
return future;
}
void OnThreadExecutor::worker_thread() {
while(!_shutdown_request) {
task_t task;
{
std::unique_lock task_lock{_task_mutex};
_task_cv.wait(task_lock, [this] { return !_task_queue.empty() || _shutdown_request; });
if(_shutdown_request) {
return;
}
task = std::move(_task_queue.front());
_task_queue.pop();
}
task();
}
}
OnThreadExecutor::~OnThreadExecutor() {
_shutdown_request = true;
_task_cv.notify_one();
_worker_thread.join();
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include <future>
#include <thread>
#include <functional>
#include <queue>
#include <atomic>
// OnThreadExecutor allows its caller to off-load some work to a persistently running background thread.
// This might come in handy if you use the API which sets thread-wide global state and the state needs
// to be isolated.
class OnThreadExecutor final {
public:
using task_t = std::packaged_task<void()>;
OnThreadExecutor();
~OnThreadExecutor();
std::future<void> submit(task_t task);
private:
void worker_thread();
std::thread _worker_thread;
std::mutex _task_mutex;
std::condition_variable _task_cv;
std::atomic_bool _shutdown_request;
std::queue<std::packaged_task<void()>> _task_queue;
};

View File

@@ -80,6 +80,22 @@ namespace PowerToysSettings {
m_json.as_object()[L"properties"].as_object()[name] = item;
}
// add_multiline_string overloads.
void Settings::add_multiline_string(const std::wstring& name, UINT description_resource_id, const std::wstring& value) {
add_multiline_string(name, get_resource(description_resource_id), value);
}
void Settings::add_multiline_string(const std::wstring& name, const std::wstring& description, const std::wstring& value) {
web::json::value item = web::json::value::object();
item.as_object()[L"display_name"] = web::json::value::string(description);
item.as_object()[L"editor_type"] = web::json::value::string(L"string_text");
item.as_object()[L"value"] = web::json::value::string(value);
item.as_object()[L"order"] = web::json::value::number(++m_curr_priority);
item.as_object()[L"multiline"] = web::json::value::boolean(true);
m_json.as_object()[L"properties"].as_object()[name] = item;
}
// add_color_picker overloads.
void Settings::add_color_picker(const std::wstring& name, UINT description_resource_id, const std::wstring& value) {
add_color_picker(name, get_resource(description_resource_id), value);

View File

@@ -31,6 +31,9 @@ namespace PowerToysSettings {
void add_string(const std::wstring& name, UINT description_resource_id, const std::wstring& value);
void add_string(const std::wstring& name, const std::wstring& description, const std::wstring& value);
void add_multiline_string(const std::wstring& name, UINT description_resource_id, const std::wstring& value);
void add_multiline_string(const std::wstring& name, const std::wstring& description, const std::wstring& value);
void add_color_picker(const std::wstring& name, UINT description_resource_id, const std::wstring& value);
void add_color_picker(const std::wstring& name, const std::wstring& description, const std::wstring& value);
@@ -117,14 +120,14 @@ namespace PowerToysSettings {
web::json::value parsed_json = web::json::value::parse(json);
return HotkeyObject(parsed_json);
}
static HotkeyObject from_settings(bool win_pressed, bool ctrl_pressed, bool alt_pressed, bool shift_pressed, UINT vk_code, const std::wstring& key) {
static HotkeyObject from_settings(bool win_pressed, bool ctrl_pressed, bool alt_pressed, bool shift_pressed, UINT vk_code) {
web::json::value json = web::json::value::object();
json.as_object()[L"win"] = web::json::value::boolean(win_pressed);
json.as_object()[L"ctrl"] = web::json::value::boolean(ctrl_pressed);
json.as_object()[L"alt"] = web::json::value::boolean(alt_pressed);
json.as_object()[L"shift"] = web::json::value::boolean(shift_pressed);
json.as_object()[L"code"] = web::json::value::number(vk_code);
json.as_object()[L"key"] = web::json::value::string(key);
json.as_object()[L"key"] = web::json::value::string(key_from_code(vk_code));
return HotkeyObject(json);
}
const web::json::value& get_json() const { return m_json; }
@@ -145,7 +148,41 @@ namespace PowerToysSettings {
return get_modifiers_repeat() | MOD_NOREPEAT;
}
protected:
HotkeyObject(web::json::value hotkey_json) : m_json(hotkey_json) {};
static std::wstring key_from_code(UINT key_code) {
auto layout = GetKeyboardLayout(0);
auto scan_code = MapVirtualKeyExW(key_code, MAPVK_VK_TO_VSC_EX, layout);
// Determinate if vk is an extended key. Unfortunatly MAPVK_VK_TO_VSC_EX
// does not return correct values.
static std::vector<UINT> extended_keys = {
VK_APPS, VK_CANCEL, VK_SNAPSHOT, VK_DIVIDE, VK_NUMLOCK, VK_LWIN, VK_RWIN, VK_RMENU,
VK_RCONTROL, VK_RSHIFT, VK_RETURN, VK_INSERT, VK_DELETE, VK_PRIOR, VK_NEXT,
VK_HOME, VK_END, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT,
};
if (find(begin(extended_keys), end(extended_keys), key_code) != end(extended_keys)) {
scan_code |= 0x100;
}
std::array<BYTE, 256> key_states{}; // Zero-initialize
std::array<wchar_t, 256> output;
auto output_bytes = ToUnicodeEx(key_code, scan_code, key_states.data(), output.data(), (int)output.size() - 1, 0, layout);
if (output_bytes <= 0) {
// If ToUnicodeEx fails (e.g. for F1-F12 keys) use GetKeyNameTextW
output_bytes = GetKeyNameTextW(scan_code << 16, output.data(), static_cast<int>(output.size()));
}
if (output_bytes > 0) {
output[output_bytes] = 0;
if (output_bytes == 1 && output[0] >= 'a' && output[0] <= 'z') {
// Make Latin letters keys capital, as it looks better
output[0] = toupper(output[0]);
}
return output.data();
}
return L"(Key " + std::to_wstring(key_code) + L")";
}
HotkeyObject(web::json::value hotkey_json) : m_json(hotkey_json) {
if (get_key() == L"~" && get_modifiers_repeat() == MOD_WIN) {
m_json.as_object()[L"key"] = web::json::value::string(key_from_code(get_code()));
}
};
web::json::value m_json;
};

View File

@@ -4,7 +4,7 @@
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 0
#define VERSION_MINOR 13
#define VERSION_MINOR 14
#define VERSION_REVISION 0
#define VERSION_BUILD 0

View File

@@ -214,6 +214,9 @@ public:
}
return 0;
}
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override { }
virtual void signal_system_menu_action(const wchar_t* name) override { }
};
// Load the settings file.

View File

@@ -3,7 +3,7 @@ Fancy Zones is a window manager that is designed to make it easy to arrange and
![Fancy Zones](FancyZones.png)
To get started with Fancy Zones, you need to enable the utility in Power Toys settings and then invoke the Fancy Zones setup UI. There is a button in settings to invoke this UI, or you can press Win+~ to launch it. When first launched, the UI presents a list of zone layouts that can be quickly adjusted by how many windows are on the monitor. Choosing a layout shows a preview of that layout on the monitor. Pressing the save and close button sets that layout to the monitor.
To get started with Fancy Zones, you need to enable the utility in Power Toys settings and then invoke the Fancy Zones setup UI. There is a button in settings to invoke this UI, or you can press Win+` (note that this shortcut can be changed in the settings dialog) to launch it. When first launched, the UI presents a list of zone layouts that can be quickly adjusted by how many windows are on the monitor. Choosing a layout shows a preview of that layout on the monitor. Pressing the save and close button sets that layout to the monitor.
![Fancy Zones Picker](Picker.png)
@@ -20,7 +20,7 @@ The backlog for the utility can be found [here](https://github.com/Microsoft/Pow
## Shortcut Keys
| Shortcut | Action |
| ----------- | ----------- |
| Win + ~ | Launches editor |
| Win + ` | Launches editor (this shortcut is editable in the settings dialog) |
| Win+Ctrl+\<Number> | Cycles through saved layouts with the corresponding number of zones |
| Win+Left/Right Arrow | Move focused window between zones (only if Override snap hotkeys setting is enabled) |

View File

@@ -1,5 +1,6 @@
#include "pch.h"
#include <common/settings_objects.h>
#include <common/common.h>
#include <interface/powertoy_module_interface.h>
#include <interface/lowlevel_keyboard_event_data.h>
#include <interface/win_hook_event_data.h>
@@ -72,10 +73,8 @@ STDAPI PersistZoneSet(
ZoneSetConfig(
id,
layoutId,
reinterpret_cast<HMONITOR>(monitor),
resolutionKey,
ZoneSetLayout::Custom,
0, 0, 0));
MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY),
resolutionKey));
for (int i = 0; i < zoneCount; i++)
{
@@ -84,7 +83,7 @@ STDAPI PersistZoneSet(
const int top = zones[baseIndex+1];
const int right = zones[baseIndex+2];
const int bottom = zones[baseIndex+3];
zoneSet->AddZone(MakeZone({ left, top, right, bottom }), false);
zoneSet->AddZone(MakeZone({ left, top, right, bottom }));
}
zoneSet->Save();
@@ -182,6 +181,9 @@ public:
return 0;
}
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override { }
virtual void signal_system_menu_action(const wchar_t* name) override { }
// Destroy the powertoy and free memory
virtual void destroy() override
{
@@ -195,11 +197,25 @@ public:
}
private:
static bool IsInterestingWindow(HWND window)
bool IsInterestingWindow(HWND window)
{
auto style = GetWindowLongPtr(window, GWL_STYLE);
auto exStyle = GetWindowLongPtr(window, GWL_EXSTYLE);
return IsWindowVisible(window) && WI_IsFlagSet(style, WS_MAXIMIZEBOX) && WI_IsFlagClear(style, WS_CHILD) && WI_IsFlagClear(exStyle, WS_EX_TOOLWINDOW);
auto windowAndPath = get_filtered_base_window_and_path(window);
if (windowAndPath.hwnd == nullptr)
{
return false;
}
CharUpperBuffW(windowAndPath.process_path.data(), (DWORD)windowAndPath.process_path.length());
if (m_settings)
{
for (const auto& excluded : m_settings->GetSettings().excludedAppsArray)
{
if (windowAndPath.process_path.find(excluded) != std::wstring::npos)
{
return false;
}
}
}
return true;
}
void Disable(bool const traceEvent)
@@ -220,6 +236,7 @@ private:
void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept;
void MoveSizeUpdate(POINT const& ptScreen) noexcept;
HANDLE m_movedWindow = nullptr;
winrt::com_ptr<IFancyZones> m_app;
winrt::com_ptr<IFancyZonesSettings> m_settings;
};
@@ -298,6 +315,7 @@ void FancyZonesModule::MoveSizeStart(HWND window, POINT const& ptScreen) noexcep
{
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
{
m_movedWindow = window;
m_app.as<IFancyZonesCallback>()->MoveSizeStart(window, monitor, ptScreen);
}
}
@@ -305,8 +323,9 @@ void FancyZonesModule::MoveSizeStart(HWND window, POINT const& ptScreen) noexcep
void FancyZonesModule::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
{
if (IsInterestingWindow(window))
if (IsInterestingWindow(window) || (window != nullptr && window == m_movedWindow))
{
m_movedWindow = nullptr;
m_app.as<IFancyZonesCallback>()->MoveSizeEnd(window, ptScreen);
}
}

View File

@@ -1,4 +1,4 @@
<Controls:MetroWindow x:Class="FancyZonesEditor.MainWindow"
<Controls:MetroWindow x:Class="FancyZonesEditor.MainWindow"
x:Name="MainWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -18,6 +18,7 @@
<Window.Resources>
<local:BooleanToBrushConverter x:Key="BooleanToBrushConverter" />
<local:ModelToVisibilityConverter x:Key="ModelToVisibilityConverter" />
<local:BooleanToIntConverter x:Key="BooleanToIntConverter" />
<Style x:Key="titleText" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI" />
@@ -176,8 +177,8 @@
<StackPanel>
<TextBlock Name="dialog_Title" Text="Choose your layout" Style="{StaticResource titleText}" />
<TabControl BorderThickness="0" x:Name="TemplateTab">
<TabControl BorderThickness="0" x:Name="TemplateTab" SelectedIndex="{Binding IsCustomLayoutActive, Mode=OneWay, Converter={StaticResource BooleanToIntConverter}}">
<TabItem Header="Templates" Template="{StaticResource myTabs}">
<StackPanel>
<StackPanel Margin="0,15,0,8" Orientation="Horizontal" HorizontalAlignment="Center">

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
@@ -23,6 +23,9 @@ namespace FancyZonesEditor
/// </summary>
public partial class MainWindow : MetroWindow
{
// TODO: share the constants b/w C# Editor and FancyZoneLib
public static int MAX_ZONES = 40;
public MainWindow()
{
InitializeComponent();
@@ -35,7 +38,8 @@ namespace FancyZonesEditor
}
private int _WrapPanelItemSize = 262;
public int WrapPanelItemSize {
public int WrapPanelItemSize
{
get
{
return _WrapPanelItemSize;
@@ -57,7 +61,7 @@ namespace FancyZonesEditor
private void IncrementZones_Click(object sender, RoutedEventArgs e)
{
if (_settings.ZoneCount < 40)
if (_settings.ZoneCount < MAX_ZONES)
{
_settings.ZoneCount++;
}
@@ -235,4 +239,23 @@ namespace FancyZonesEditor
return null;
}
}
public class BooleanToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return (bool)value == true ? 1 : 0;
}
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is int)
{
return (int)value == 1;
}
return false;
}
}
}

View File

@@ -22,6 +22,21 @@ namespace FancyZonesEditor
//
public class Settings : INotifyPropertyChanged
{
public bool IsCustomLayoutActive
{
get
{
foreach (LayoutModel model in CustomModels)
{
if (model.IsSelected)
{
return true;
}
}
return false;
}
}
public Settings()
{
ParseCommandLineArgs();
@@ -279,7 +294,7 @@ namespace FancyZonesEditor
// 1 = unique key for per-monitor settings
// 2 = layoutid used to generate current layout (used to pick the default layout to show)
// 3 = handle to monitor (passed back to engine to persist data)
// 4 = X_Y_Width_Height (where EditorOverlay shows up)
// 4 = X_Y_Width_Height in a dpi-scaled-but-unaware coords (where EditorOverlay shows up)
// 5 = resolution key (passed back to engine to persist data)
// 6 = monitor DPI (float)

View File

@@ -51,5 +51,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.13.0.0")]
[assembly: AssemblyFileVersion("0.13.0.0")]
[assembly: AssemblyVersion("0.14.0.0")]
[assembly: AssemblyFileVersion("0.14.0.0")]

View File

@@ -1,13 +1,14 @@
#include "pch.h"
#include "common/dpi_aware.h"
#include "common/on_thread_executor.h"
struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZonesCallback, IZoneWindowHost>
{
public:
FancyZones(HINSTANCE hinstance, IFancyZonesSettings* settings) noexcept
: m_hinstance(hinstance)
, m_settings(settings)
{
m_settings.attach(settings);
m_settings->SetCallback(this);
}
@@ -27,7 +28,6 @@ public:
IFACEMETHODIMP_(void) SettingsChanged() noexcept;
// IZoneWindowHost
IFACEMETHODIMP_(void) ToggleZoneViewers() noexcept;
IFACEMETHODIMP_(void) MoveWindowsOnActiveZoneSetChange() noexcept;
IFACEMETHODIMP_(COLORREF) GetZoneHighlightColor() noexcept
{
@@ -42,7 +42,6 @@ public:
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
void OnDisplayChange(DisplayChangeType changeType) noexcept;
void ShowZoneEditorForMonitor(HMONITOR monitor) noexcept;
void AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept;
void MoveWindowIntoZoneByIndex(HWND window, int index) noexcept;
@@ -79,18 +78,20 @@ private:
mutable std::shared_mutex m_lock;
HWND m_window{};
HWND m_windowMoveSize{}; // The window that is being moved/sized
bool m_editorsVisible{}; // Are we showing the zone editors?
bool m_inMoveSize{}; // Whether or not a move/size operation is currently active
bool m_dragEnabled{}; // True if we should be showing zone hints while dragging
std::map<HMONITOR, winrt::com_ptr<IZoneWindow>> m_zoneWindowMap; // Map of monitor to ZoneWindow (one per monitor)
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors.
winrt::com_ptr<IFancyZonesSettings> m_settings;
GUID m_currentVirtualDesktopId{};
wil::unique_handle m_terminateEditorEvent;
IFancyZonesSettings* m_settings{};
GUID m_currentVirtualDesktopId{}; // UUID of the current virtual desktop. Is GUID_NULL until first VD switch per session.
wil::unique_handle m_terminateEditorEvent; // Handle of FancyZonesEditor.exe we launch and wait on
static UINT WM_PRIV_VDCHANGED;
static UINT WM_PRIV_EDITOR;
OnThreadExecutor m_dpiUnawareThread;
static UINT WM_PRIV_VDCHANGED; // Message to get back on to the UI thread when virtual desktop changes
static UINT WM_PRIV_EDITOR; // Message to get back on to the UI thread when the editor exits
// Did we terminate the editor or was it closed cleanly?
enum class EditorExitKind : byte
{
Exit,
@@ -119,14 +120,20 @@ IFACEMETHODIMP_(void) FancyZones::Run() noexcept
if (!m_window) return;
RegisterHotKey(m_window, 1, m_settings->GetSettings().editorHotkey.get_modifiers(), m_settings->GetSettings().editorHotkey.get_code());
VirtualDesktopChanged();
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{[]{
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR_MIXED);
}}).wait();
}
// IFancyZones
IFACEMETHODIMP_(void) FancyZones::Destroy() noexcept
{
std::unique_lock writeLock(m_lock);
m_zoneWindowMap.clear();
BufferedPaintUnInit();
if (m_window)
{
@@ -190,33 +197,34 @@ IFACEMETHODIMP_(bool) FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
bool const win = GetAsyncKeyState(VK_LWIN) & 0x8000;
if (win && !shift)
{
if (!m_settings->GetSettings().overrideSnapHotkeys)
{
return false;
}
bool const ctrl = GetAsyncKeyState(VK_CONTROL) & 0x8000;
if (ctrl)
{
if ((info->vkCode >= '0') && (info->vkCode <= '9'))
{
Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /* inMoveSize */);
// Win+Ctrl+Number will cycle through ZoneSets
Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/);
CycleActiveZoneSet(info->vkCode);
return true;
}
}
else if ((info->vkCode == VK_RIGHT) || (info->vkCode == VK_LEFT))
{
Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /* inMoveSize */);
OnSnapHotkey(info->vkCode);
return true;
if (m_settings->GetSettings().overrideSnapHotkeys)
{
// Win+Left, Win+Right will cycle through Zones in the active ZoneSet
Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/);
OnSnapHotkey(info->vkCode);
return true;
}
}
}
else if (m_inMoveSize && (info->vkCode >= '0') && (info->vkCode <= '9'))
{
Trace::FancyZones::OnKeyDown(info->vkCode, win, false /* control */, true/* inMoveSize */);
// This allows you to cycle through ZoneSets while dragging a window
Trace::FancyZones::OnKeyDown(info->vkCode, win, false /*control*/, true /*inMoveSize*/);
CycleActiveZoneSet(info->vkCode);
return true;
return false;
}
return false;
}
@@ -239,22 +247,22 @@ void FancyZones::ToggleEditor() noexcept
}
HMONITOR monitor{};
UINT dpi_x = 96;
UINT dpi_y = 96;
HWND foregroundWindow{};
if (m_settings->GetSettings().use_cursorpos_editor_startupscreen)
UINT dpi_x = DPIAware::DEFAULT_DPI;
UINT dpi_y = DPIAware::DEFAULT_DPI;
const bool use_cursorpos_editor_startupscreen = m_settings->GetSettings().use_cursorpos_editor_startupscreen;
POINT currentCursorPos{};
if (use_cursorpos_editor_startupscreen)
{
POINT currentCursorPos{};
GetCursorPos(&currentCursorPos);
monitor = MonitorFromPoint(currentCursorPos, MONITOR_DEFAULTTOPRIMARY);
DPIAware::GetScreenDPIForPoint(currentCursorPos, dpi_x, dpi_y);
}
else
{
const HWND foregroundWindow = GetForegroundWindow();
foregroundWindow = GetForegroundWindow();
monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTOPRIMARY);
DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y);
}
@@ -272,21 +280,33 @@ void FancyZones::ToggleEditor() noexcept
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(monitor, &mi);
// X/Y need to start in unscaled screen coordinates to get to the proper top/left of the monitor
// From there, we need to scale the difference between the monitor and workarea rects to get the
// appropriate offset where the overlay should appear.
// This covers the cases where the taskbar is not at the bottom of the screen.
const auto x = mi.rcMonitor.left + MulDiv(mi.rcWork.left - mi.rcMonitor.left, 96, dpi_x);
const auto y = mi.rcMonitor.top + MulDiv(mi.rcWork.top - mi.rcMonitor.top, 96, dpi_y);
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{[&]{
GetMonitorInfo(monitor, &mi);
}}).wait();
// Location that the editor should occupy, scaled by DPI
std::wstring editorLocation =
if(use_cursorpos_editor_startupscreen)
{
DPIAware::GetScreenDPIForPoint(currentCursorPos, dpi_x, dpi_y);
}
else
{
DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y);
}
const auto taskbar_x_offset = MulDiv(mi.rcWork.left - mi.rcMonitor.left, DPIAware::DEFAULT_DPI, dpi_x);
const auto taskbar_y_offset = MulDiv(mi.rcWork.top - mi.rcMonitor.top, DPIAware::DEFAULT_DPI, dpi_y);
// Do not scale window params by the dpi, that will be done in the editor - see LayoutModel.Apply
const auto x = mi.rcMonitor.left + taskbar_x_offset;
const auto y = mi.rcMonitor.top + taskbar_y_offset;
const auto width = mi.rcWork.right - mi.rcWork.left;
const auto height = mi.rcWork.bottom - mi.rcWork.top;
const std::wstring editorLocation =
std::to_wstring(x) + L"_" +
std::to_wstring(y) + L"_" +
std::to_wstring(MulDiv(mi.rcWork.right - mi.rcWork.left, 96, dpi_x)) + L"_" +
std::to_wstring(MulDiv(mi.rcWork.bottom - mi.rcWork.top, 96, dpi_y));
std::to_wstring(width) + L"_" +
std::to_wstring(height);
const std::wstring params =
iter->second->UniqueId() + L" " +
@@ -294,7 +314,7 @@ void FancyZones::ToggleEditor() noexcept
std::to_wstring(reinterpret_cast<UINT_PTR>(monitor)) + L" " +
editorLocation + L" " +
iter->second->WorkAreaKey() + L" " +
std::to_wstring(static_cast<float>(dpi_x) / 96.0f);
std::to_wstring(static_cast<float>(dpi_x) / DPIAware::DEFAULT_DPI);
SHELLEXECUTEINFO sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
@@ -336,38 +356,6 @@ void FancyZones::SettingsChanged() noexcept
RegisterHotKey(m_window, 1, m_settings->GetSettings().editorHotkey.get_modifiers(), m_settings->GetSettings().editorHotkey.get_code());
}
// IZoneWindowHost
IFACEMETHODIMP_(void) FancyZones::ToggleZoneViewers() noexcept
{
bool alreadyVisible{};
{
std::unique_lock writeLock(m_lock);
alreadyVisible = m_editorsVisible;
m_editorsVisible = !alreadyVisible;
}
Trace::FancyZones::ToggleZoneViewers(!alreadyVisible);
if (!alreadyVisible)
{
auto callback = [](HMONITOR monitor, HDC, RECT *, LPARAM data) -> BOOL
{
auto strongThis = reinterpret_cast<FancyZones*>(data);
strongThis->ShowZoneEditorForMonitor(monitor);
return TRUE;
};
EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast<LPARAM>(this));
}
else
{
std::shared_lock readLock(m_lock);
for (auto iter : m_zoneWindowMap)
{
iter.second->HideZoneWindow();
}
}
}
// IZoneWindowHost
IFACEMETHODIMP_(void) FancyZones::MoveWindowsOnActiveZoneSetChange() noexcept
{
@@ -385,14 +373,7 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
{
if (wparam == 1)
{
if (m_settings->GetSettings().use_standalone_editor)
{
ToggleEditor();
}
else
{
ToggleZoneViewers();
}
ToggleEditor();
}
}
break;
@@ -488,18 +469,6 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
}
}
void FancyZones::ShowZoneEditorForMonitor(HMONITOR monitor) noexcept
{
std::shared_lock readLock(m_lock);
auto iter = m_zoneWindowMap.find(monitor);
if (iter != m_zoneWindowMap.end())
{
bool const activate = MonitorFromPoint(POINT(), MONITOR_DEFAULTTOPRIMARY) == monitor;
iter->second->ShowZoneWindow(activate, false /*fadeIn*/);
}
}
void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
{
std::unique_lock writeLock(m_lock);
@@ -652,34 +621,40 @@ void FancyZones::MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT cons
RECT windowRect{};
::GetWindowRect(window, &windowRect);
windowRect.top += 6;
windowRect.left += 8;
windowRect.right -= 8;
windowRect.bottom -= 6;
const auto padding_x = 8;
const auto padding_y = 6;
windowRect.top += padding_y;
windowRect.left += padding_x;
windowRect.right -= padding_x;
windowRect.bottom -= padding_y;
if (PtInRect(&windowRect, ptScreen))
if (PtInRect(&windowRect, ptScreen) == FALSE)
{
m_inMoveSize = true;
return;
}
auto iter = m_zoneWindowMap.find(monitor);
if (iter != m_zoneWindowMap.end())
{
m_windowMoveSize = window;
m_inMoveSize = true;
// This updates m_dragEnabled depending on if the shift key is being held down.
UpdateDragState(writeLock);
auto iter = m_zoneWindowMap.find(monitor);
if (iter == end(m_zoneWindowMap))
{
return;
}
if (m_dragEnabled)
{
m_zoneWindowMoveSize = iter->second;
m_zoneWindowMoveSize->MoveSizeEnter(window, m_dragEnabled);
}
else if (m_zoneWindowMoveSize)
{
m_zoneWindowMoveSize->MoveSizeCancel();
m_zoneWindowMoveSize = nullptr;
}
}
m_windowMoveSize = window;
// This updates m_dragEnabled depending on if the shift key is being held down.
UpdateDragState(writeLock);
if (m_dragEnabled)
{
m_zoneWindowMoveSize = iter->second;
m_zoneWindowMoveSize->MoveSizeEnter(window, m_dragEnabled);
}
else if (m_zoneWindowMoveSize)
{
m_zoneWindowMoveSize->MoveSizeCancel();
m_zoneWindowMoveSize = nullptr;
}
}

View File

@@ -32,7 +32,6 @@ interface __declspec(uuid("{2CB37E8F-87E6-4AEC-B4B2-E0FDC873343F}")) IFancyZones
interface __declspec(uuid("{5C8D99D6-34B2-4F4A-A8E5-7483F6869775}")) IZoneWindowHost : public IUnknown
{
IFACEMETHOD_(void, ToggleZoneViewers)() = 0;
IFACEMETHOD_(void, MoveWindowsOnActiveZoneSetChange)() = 0;
IFACEMETHOD_(COLORREF, GetZoneHighlightColor)() = 0;
};

View File

@@ -11,7 +11,7 @@ public:
LoadSettings(name, true /*fromFile*/);
}
IFACEMETHODIMP_(void) SetCallback(IFancyZonesCallback* callback) { m_callback.attach(callback); }
IFACEMETHODIMP_(void) SetCallback(IFancyZonesCallback* callback) { m_callback = callback; }
IFACEMETHODIMP_(bool) GetConfig(_Out_ PWSTR buffer, _Out_ int *buffer_sizeg) noexcept;
IFACEMETHODIMP_(void) SetConfig(PCWSTR config) noexcept;
IFACEMETHODIMP_(void) CallCustomAction(PCWSTR action) noexcept;
@@ -21,7 +21,7 @@ private:
void LoadSettings(PCWSTR config, bool fromFile) noexcept;
void SaveSettings() noexcept;
winrt::com_ptr<IFancyZonesCallback> m_callback;
IFancyZonesCallback* m_callback{};
const HINSTANCE m_hinstance;
PCWSTR m_name{};
@@ -32,7 +32,7 @@ private:
PCWSTR name;
bool* value;
int resourceId;
} m_configBools[9] = {
} m_configBools[8] = {
{ L"fancyzones_shiftDrag", &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG },
{ L"fancyzones_overrideSnapHotkeys", &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS },
{ L"fancyzones_zoneSetChange_flashZones", &m_settings.zoneSetChange_flashZones, IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES },
@@ -40,19 +40,12 @@ private:
{ L"fancyzones_zoneSetChange_moveWindows", &m_settings.zoneSetChange_moveWindows, IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS },
{ L"fancyzones_virtualDesktopChange_moveWindows", &m_settings.virtualDesktopChange_moveWindows, IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS },
{ L"fancyzones_appLastZone_moveWindows", &m_settings.appLastZone_moveWindows, IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS },
{ L"fancyzones_use_standalone_editor", &m_settings.use_standalone_editor, IDS_SETTING_DESCRIPTION_USE_STANDALONE_EDITOR },
{ L"use_cursorpos_editor_startupscreen", &m_settings.use_cursorpos_editor_startupscreen, IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN },
};
struct
{
PCWSTR name;
std::wstring* value;
int resourceId;
} m_configStrings[1] = {
{ L"fancyzones_zoneHighlightColor", &m_settings.zoneHightlightColor, IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR },
};
const std::wstring m_editor_hotkey_name = L"fancyzones_editor_hotkey";
const std::wstring m_zoneHiglightName = L"fancyzones_zoneHighlightColor";
const std::wstring m_editorHotkeyName = L"fancyzones_editor_hotkey";
const std::wstring m_excludedAppsName = L"fancyzones_excluded_apps";
};
IFACEMETHODIMP_(bool) FancyZonesSettings::GetConfig(_Out_ PWSTR buffer, _Out_ int *buffer_size) noexcept
@@ -73,17 +66,15 @@ IFACEMETHODIMP_(bool) FancyZonesSettings::GetConfig(_Out_ PWSTR buffer, _Out_ in
IDS_SETTING_LAUNCH_EDITOR_BUTTON,
IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION
);
settings.add_hotkey(m_editor_hotkey_name, IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, m_settings.editorHotkey);
settings.add_hotkey(m_editorHotkeyName, IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, m_settings.editorHotkey);
for (auto const& setting : m_configBools)
{
settings.add_bool_toogle(setting.name, setting.resourceId, *setting.value);
}
for (auto const& setting : m_configStrings)
{
settings.add_color_picker(setting.name, setting.resourceId, *setting.value);
}
settings.add_color_picker(m_zoneHiglightName, IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR, m_settings.zoneHightlightColor);
settings.add_multiline_string(m_excludedAppsName, IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION, m_settings.excludedApps);
return settings.serialize_to_buffer(buffer, buffer_size);
}
@@ -127,17 +118,37 @@ void FancyZonesSettings::LoadSettings(PCWSTR config, bool fromFile) noexcept try
}
}
for (auto const& setting : m_configStrings)
if (values.is_string_value(m_zoneHiglightName))
{
if (values.is_string_value(setting.name))
{
*setting.value = values.get_string_value(setting.name);
}
m_settings.zoneHightlightColor = values.get_string_value(m_zoneHiglightName);
}
if (values.is_object_value(m_editor_hotkey_name))
if (values.is_object_value(m_editorHotkeyName))
{
m_settings.editorHotkey = PowerToysSettings::HotkeyObject::from_json(values.get_json(m_editor_hotkey_name));
m_settings.editorHotkey = PowerToysSettings::HotkeyObject::from_json(values.get_json(m_editorHotkeyName));
}
if (values.is_string_value(m_excludedAppsName))
{
m_settings.excludedApps = values.get_string_value(m_excludedAppsName);
m_settings.excludedAppsArray.clear();
auto excludedUppercase = m_settings.excludedApps;
CharUpperBuffW(excludedUppercase.data(), (DWORD)excludedUppercase.length());
std::wstring_view view(excludedUppercase);
while (view.starts_with('\n') || view.starts_with('\r'))
{
view.remove_prefix(1);
}
while (!view.empty())
{
auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length());
m_settings.excludedAppsArray.emplace_back(view.substr(0, pos));
view.remove_prefix(pos);
while (view.starts_with('\n') || view.starts_with('\r'))
{
view.remove_prefix(1);
}
}
}
}
CATCH_LOG();
@@ -151,12 +162,9 @@ void FancyZonesSettings::SaveSettings() noexcept try
values.add_property(setting.name, *setting.value);
}
for (auto const& setting : m_configStrings)
{
values.add_property(setting.name, *setting.value);
}
values.add_property(m_editor_hotkey_name, m_settings.editorHotkey);
values.add_property(m_zoneHiglightName, m_settings.zoneHightlightColor);
values.add_property(m_editorHotkeyName, m_settings.editorHotkey);
values.add_property(m_excludedAppsName, m_settings.excludedApps);
values.save_to_settings_file();
}

View File

@@ -13,10 +13,11 @@ struct Settings
bool zoneSetChange_moveWindows = false;
bool overrideSnapHotkeys = false;
bool appLastZone_moveWindows = false;
bool use_standalone_editor = true;
bool use_cursorpos_editor_startupscreen = true;
std::wstring zoneHightlightColor = L"#0078D7";
PowerToysSettings::HotkeyObject editorHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, false, VK_OEM_3, L"~");
PowerToysSettings::HotkeyObject editorHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, false, VK_OEM_3);
std::wstring excludedApps = L"";
std::vector<std::wstring> excludedAppsArray;
};
interface __declspec(uuid("{BA4E77C4-6F44-4C5D-93D3-CBDE880495C2}")) IFancyZonesSettings : public IUnknown

View File

@@ -5,10 +5,6 @@ struct ZoneSet : winrt::implements<ZoneSet, IZoneSet>
public:
ZoneSet(ZoneSetConfig const& config) : m_config(config)
{
if (config.ZoneCount > 0)
{
InitialPopulateZones();
}
}
ZoneSet(ZoneSetConfig const& config, std::vector<winrt::com_ptr<IZone>> zones) :
@@ -19,44 +15,25 @@ public:
IFACEMETHODIMP_(GUID) Id() noexcept { return m_config.Id; }
IFACEMETHODIMP_(WORD) LayoutId() noexcept { return m_config.LayoutId; }
IFACEMETHODIMP AddZone(winrt::com_ptr<IZone> zone, bool front) noexcept;
IFACEMETHODIMP RemoveZone(winrt::com_ptr<IZone> zone) noexcept;
IFACEMETHODIMP AddZone(winrt::com_ptr<IZone> zone) noexcept;
IFACEMETHODIMP_(winrt::com_ptr<IZone>) ZoneFromPoint(POINT pt) noexcept;
IFACEMETHODIMP_(winrt::com_ptr<IZone>) ZoneFromWindow(HWND window) noexcept;
IFACEMETHODIMP_(int) GetZoneIndexFromWindow(HWND window) noexcept;
IFACEMETHODIMP_(std::vector<winrt::com_ptr<IZone>>) GetZones() noexcept { return m_zones; }
IFACEMETHODIMP_(ZoneSetLayout) GetLayout() noexcept { return m_config.Layout; }
IFACEMETHODIMP_(int) GetInnerPadding() noexcept { return m_config.PaddingInner; }
IFACEMETHODIMP_(winrt::com_ptr<IZoneSet>) MakeCustomClone() noexcept;
IFACEMETHODIMP_(void) Save() noexcept;
IFACEMETHODIMP_(void) MoveZoneToFront(winrt::com_ptr<IZone> zone) noexcept;
IFACEMETHODIMP_(void) MoveZoneToBack(winrt::com_ptr<IZone> zone) noexcept;
IFACEMETHODIMP_(void) MoveWindowIntoZoneByIndex(HWND window, HWND zoneWindow, int index) noexcept;
IFACEMETHODIMP_(void) MoveWindowIntoZoneByDirection(HWND window, HWND zoneWindow, DWORD vkCode) noexcept;
IFACEMETHODIMP_(void) MoveSizeEnd(HWND window, HWND zoneWindow, POINT ptClient) noexcept;
private:
void InitialPopulateZones() noexcept;
void GenerateGridZones(MONITORINFO const& mi) noexcept;
void DoGridLayout(SIZE const& zoneArea, int numCols, int numRows) noexcept;
void GenerateFocusZones(MONITORINFO const& mi) noexcept;
void StampZone(HWND window, _In_opt_ winrt::com_ptr<IZone> zone) noexcept;
winrt::com_ptr<IZone> ZoneFromWindow(HWND window) noexcept;
std::vector<winrt::com_ptr<IZone>> m_zones;
ZoneSetConfig m_config;
};
IFACEMETHODIMP ZoneSet::AddZone(winrt::com_ptr<IZone> zone, bool front) noexcept
IFACEMETHODIMP ZoneSet::AddZone(winrt::com_ptr<IZone> zone) noexcept
{
// XXXX: need to reorder ids when inserting...
if (front)
{
m_zones.insert(m_zones.begin(), zone);
}
else
{
m_zones.emplace_back(zone);
}
m_zones.emplace_back(zone);
// Important not to set Id 0 since we store it in the HWND using SetProp.
// SetProp(0) doesn't really work.
@@ -64,17 +41,6 @@ IFACEMETHODIMP ZoneSet::AddZone(winrt::com_ptr<IZone> zone, bool front) noexcept
return S_OK;
}
IFACEMETHODIMP ZoneSet::RemoveZone(winrt::com_ptr<IZone> zone) noexcept
{
auto iter = std::find(m_zones.begin(), m_zones.end(), zone);
if (iter != m_zones.end())
{
m_zones.erase(iter);
return S_OK;
}
return E_INVALIDARG;
}
IFACEMETHODIMP_(winrt::com_ptr<IZone>) ZoneSet::ZoneFromPoint(POINT pt) noexcept
{
winrt::com_ptr<IZone> smallestKnownZone = nullptr;
@@ -111,31 +77,6 @@ IFACEMETHODIMP_(winrt::com_ptr<IZone>) ZoneSet::ZoneFromPoint(POINT pt) noexcept
return smallestKnownZone;
}
IFACEMETHODIMP_(winrt::com_ptr<IZone>) ZoneSet::ZoneFromWindow(HWND window) noexcept
{
for (auto iter = m_zones.begin(); iter != m_zones.end(); iter++)
{
if (winrt::com_ptr<IZone> zone = iter->try_as<IZone>())
{
if (zone->ContainsWindow(window))
{
return zone;
}
}
}
return nullptr;
}
IFACEMETHODIMP_(winrt::com_ptr<IZoneSet>) ZoneSet::MakeCustomClone() noexcept
{
if (SUCCEEDED_LOG(CoCreateGuid(&m_config.Id)))
{
m_config.IsCustom = true;
return winrt::make_self<ZoneSet>(m_config, m_zones);
}
return nullptr;
}
IFACEMETHODIMP_(void) ZoneSet::Save() noexcept
{
size_t const zoneCount = m_zones.size();
@@ -148,9 +89,6 @@ IFACEMETHODIMP_(void) ZoneSet::Save() noexcept
ZoneSetPersistedData data{};
data.LayoutId = m_config.LayoutId;
data.ZoneCount = static_cast<DWORD>(zoneCount);
data.Layout = m_config.Layout;
data.PaddingInner = m_config.PaddingInner;
data.PaddingOuter = m_config.PaddingOuter;
int i = 0;
for (auto iter = m_zones.begin(); iter != m_zones.end(); iter++)
@@ -170,24 +108,6 @@ IFACEMETHODIMP_(void) ZoneSet::Save() noexcept
}
}
IFACEMETHODIMP_(void) ZoneSet::MoveZoneToFront(winrt::com_ptr<IZone> zone) noexcept
{
auto iter = std::find(m_zones.begin(), m_zones.end(), zone);
if (iter != m_zones.end())
{
std::rotate(m_zones.begin(), iter, iter + 1);
}
}
IFACEMETHODIMP_(void) ZoneSet::MoveZoneToBack(winrt::com_ptr<IZone> zone) noexcept
{
auto iter = std::find(m_zones.begin(), m_zones.end(), zone);
if (iter != m_zones.end())
{
std::rotate(iter, iter + 1, m_zones.end());
}
}
IFACEMETHODIMP_(int) ZoneSet::GetZoneIndexFromWindow(HWND window) noexcept
{
int zoneIndex = 0;
@@ -273,127 +193,19 @@ IFACEMETHODIMP_(void) ZoneSet::MoveSizeEnd(HWND window, HWND zoneWindow, POINT p
}
}
void ZoneSet::InitialPopulateZones() noexcept
winrt::com_ptr<IZone> ZoneSet::ZoneFromWindow(HWND window) noexcept
{
// TODO: reconcile the pregenerated FZ layouts with the editor
MONITORINFO mi{};
mi.cbSize = sizeof(mi);
if (GetMonitorInfoW(m_config.Monitor, &mi))
for (auto iter = m_zones.begin(); iter != m_zones.end(); iter++)
{
if ((m_config.Layout == ZoneSetLayout::Grid) || (m_config.Layout == ZoneSetLayout::Row))
if (winrt::com_ptr<IZone> zone = iter->try_as<IZone>())
{
GenerateGridZones(mi);
}
else if (m_config.Layout == ZoneSetLayout::Focus)
{
GenerateFocusZones(mi);
}
Save();
}
}
void ZoneSet::GenerateGridZones(MONITORINFO const& mi) noexcept
{
Rect workArea(mi.rcWork);
int numCols, numRows;
if (m_config.Layout == ZoneSetLayout::Grid)
{
switch (m_config.ZoneCount)
{
case 1: numCols = 1; numRows = 1; break;
case 2: numCols = 2; numRows = 1; break;
case 3: numCols = 2; numRows = 2; break;
case 4: numCols = 2; numRows = 2; break;
case 5: numCols = 3; numRows = 3; break;
case 6: numCols = 3; numRows = 3; break;
case 7: numCols = 3; numRows = 3; break;
case 8: numCols = 3; numRows = 3; break;
case 9: numCols = 3; numRows = 3; break;
}
if ((m_config.ZoneCount == 2) && (workArea.height() > workArea.width()))
{
numCols = 1;
numRows = 2;
if (zone->ContainsWindow(window))
{
return zone;
}
}
}
else if (m_config.Layout == ZoneSetLayout::Row)
{
numCols = m_config.ZoneCount;
numRows = 1;
}
SIZE const zoneArea = {
workArea.width() - ((m_config.PaddingOuter * 2) + (m_config.PaddingInner * (numCols - 1))),
workArea.height() - ((m_config.PaddingOuter * 2) + (m_config.PaddingInner * (numRows - 1)))
};
DoGridLayout(zoneArea, numCols, numRows);
}
void ZoneSet::DoGridLayout(SIZE const& zoneArea, int numCols, int numRows) noexcept
{
auto x = m_config.PaddingOuter;
auto y = m_config.PaddingOuter;
auto const zoneWidth = (zoneArea.cx / numCols);
auto const zoneHeight = (zoneArea.cy / numRows);
for (auto i = 1; i <= m_config.ZoneCount; i++)
{
auto col = numCols - (i % numCols);
RECT const zoneRect = { x, y, x + zoneWidth, y + zoneHeight };
AddZone(MakeZone(zoneRect), false);
x += zoneWidth + m_config.PaddingInner;
if (col == numCols)
{
x = m_config.PaddingOuter;
y += zoneHeight + m_config.PaddingInner;
}
}
}
void ZoneSet::GenerateFocusZones(MONITORINFO const& mi) noexcept
{
Rect const workArea(mi.rcWork);
SIZE const workHalf = { workArea.width() / 2, workArea.height() / 2 };
RECT const safeZone = {
m_config.PaddingOuter,
m_config.PaddingOuter,
workArea.width() - m_config.PaddingOuter,
workArea.height() - m_config.PaddingOuter
};
int const width = min(1920, workArea.width() * 60 / 100);
int const height = min(1200, workArea.height() * 75 / 100);
int const halfWidth = width / 2;
int const halfHeight = height / 2;
int x = workHalf.cx - halfWidth;
int y = workHalf.cy - halfHeight;
RECT const focusRect = { x, y, x + width, y + height };
AddZone(MakeZone(focusRect), false);
for (auto i = 2; i <= m_config.ZoneCount; i++)
{
switch (i)
{
case 2: x = focusRect.right - halfWidth; y = focusRect.top + m_config.PaddingInner; break; // right
case 3: x = focusRect.left - halfWidth; y = focusRect.top + (m_config.PaddingInner * 2); break; // left
case 4: x = focusRect.left + m_config.PaddingInner; y = focusRect.top - halfHeight; break; // up
case 5: x = focusRect.left - m_config.PaddingInner; y = focusRect.bottom - halfHeight; break; // down
}
// Bound into safe zone
x = min(safeZone.right - width, max(safeZone.left, x));
y = min(safeZone.bottom - height, max(safeZone.top, y));
RECT const zoneRect = { x, y, x + width, y + height };
AddZone(MakeZone(zoneRect), false);
}
return nullptr;
}
winrt::com_ptr<IZoneSet> MakeZoneSet(ZoneSetConfig const& config) noexcept

View File

@@ -14,18 +14,11 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
{
IFACEMETHOD_(GUID, Id)() = 0;
IFACEMETHOD_(WORD, LayoutId)() = 0;
IFACEMETHOD(AddZone)(winrt::com_ptr<IZone> zone, bool front) = 0;
IFACEMETHOD(RemoveZone)(winrt::com_ptr<IZone> zone) = 0;
IFACEMETHOD(AddZone)(winrt::com_ptr<IZone> zone) = 0;
IFACEMETHOD_(winrt::com_ptr<IZone>, ZoneFromPoint)(POINT pt) = 0;
IFACEMETHOD_(winrt::com_ptr<IZone>, ZoneFromWindow)(HWND window) = 0;
IFACEMETHOD_(int, GetZoneIndexFromWindow)(HWND window) = 0;
IFACEMETHOD_(std::vector<winrt::com_ptr<IZone>>, GetZones)() = 0;
IFACEMETHOD_(ZoneSetLayout, GetLayout)() = 0;
IFACEMETHOD_(int, GetInnerPadding)() = 0;
IFACEMETHOD_(winrt::com_ptr<IZoneSet>, MakeCustomClone)() = 0;
IFACEMETHOD_(void, Save)() = 0;
IFACEMETHOD_(void, MoveZoneToFront)(winrt::com_ptr<IZone> zone) = 0;
IFACEMETHOD_(void, MoveZoneToBack)(winrt::com_ptr<IZone> zone) = 0;
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(HWND window, HWND zoneWindow, int index) = 0;
IFACEMETHOD_(void, MoveWindowIntoZoneByDirection)(HWND window, HWND zoneWindow, DWORD vkCode) = 0;
IFACEMETHOD_(void, MoveSizeEnd)(HWND window, HWND zoneWindow, POINT ptClient) = 0;
@@ -34,13 +27,15 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
#define VERSION_PERSISTEDDATA 0x0000F00D
struct ZoneSetPersistedData
{
static constexpr inline size_t MAX_ZONES = 40;
DWORD Version{VERSION_PERSISTEDDATA};
WORD LayoutId{};
DWORD ZoneCount{};
ZoneSetLayout Layout{};
DWORD PaddingInner{};
DWORD PaddingOuter{};
RECT Zones[40]{};
RECT Zones[MAX_ZONES]{};
};
struct ZoneSetConfig
@@ -49,19 +44,11 @@ struct ZoneSetConfig
GUID id,
WORD layoutId,
HMONITOR monitor,
PCWSTR resolutionKey,
ZoneSetLayout layout,
int zoneCount,
int paddingOuter,
int paddingInner) noexcept :
PCWSTR resolutionKey) noexcept :
Id(id),
LayoutId(layoutId),
Monitor(monitor),
ResolutionKey(resolutionKey),
Layout(layout),
ZoneCount(zoneCount),
PaddingOuter(paddingOuter),
PaddingInner(paddingInner)
ResolutionKey(resolutionKey)
{
}
@@ -69,11 +56,6 @@ struct ZoneSetConfig
WORD LayoutId{};
HMONITOR Monitor{};
PCWSTR ResolutionKey{};
ZoneSetLayout Layout{};
int ZoneCount{};
int PaddingOuter{};
int PaddingInner{};
bool IsCustom{};
};
winrt::com_ptr<IZoneSet> MakeZoneSet(ZoneSetConfig const& config) noexcept;

File diff suppressed because it is too large Load Diff

View File

@@ -3,8 +3,6 @@
interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow : public IUnknown
{
IFACEMETHOD(ShowZoneWindow)(bool activate, bool fadeIn) = 0;
IFACEMETHOD(HideZoneWindow)() = 0;
IFACEMETHOD(MoveSizeEnter)(HWND window, bool dragEnabled) = 0;
IFACEMETHOD(MoveSizeUpdate)(POINT const& ptScreen, bool dragEnabled) = 0;
IFACEMETHOD(MoveSizeEnd)(HWND window, POINT const& ptScreen) = 0;

View File

@@ -6,10 +6,10 @@
#define IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS 106
#define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 107
#define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 108
#define IDS_SETTING_DESCRIPTION_USE_STANDALONE_EDITOR 109
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 110
#define IDS_SETTING_DESCRIPTION 111
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 112
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 113
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 114
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 115
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 109
#define IDS_SETTING_DESCRIPTION 110
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 111
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 112
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 113
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 114
#define IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION 115

View File

@@ -12,7 +12,6 @@ struct ZoneSetInfo
{
size_t NumberOfZones = 0;
size_t NumberOfWindows = 0;
ZoneSetLayout Layout = ZoneSetLayout::Custom;
};
ZoneSetInfo GetZoneSetInfo(_In_opt_ winrt::com_ptr<IZoneSet> set) noexcept
@@ -22,7 +21,6 @@ ZoneSetInfo GetZoneSetInfo(_In_opt_ winrt::com_ptr<IZoneSet> set) noexcept
{
auto zones = set->GetZones();
info.NumberOfZones = zones.size();
info.Layout = set->GetLayout();
info.NumberOfWindows = std::count_if(zones.cbegin(), zones.cend(), [&](winrt::com_ptr<IZone> zone)
{
return !zone->IsEmpty();
@@ -31,7 +29,6 @@ ZoneSetInfo GetZoneSetInfo(_In_opt_ winrt::com_ptr<IZoneSet> set) noexcept
return info;
}
void Trace::RegisterProvider() noexcept
{
TraceLoggingRegister(g_hProvider);
@@ -52,16 +49,6 @@ void Trace::FancyZones::EnableFancyZones(bool enabled) noexcept
TraceLoggingBoolean(enabled, "Enabled"));
}
void Trace::FancyZones::ToggleZoneViewers(bool visible) noexcept
{
TraceLoggingWrite(
g_hProvider,
"FancyZones_ToggleZoneViewers",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingBoolean(visible, "Visible"));
}
void Trace::FancyZones::OnKeyDown(DWORD vkCode, bool win, bool control, bool inMoveSize) noexcept
{
TraceLoggingWrite(
@@ -100,15 +87,14 @@ void Trace::VirtualDesktopChanged() noexcept
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}
void Trace::ZoneWindow::KeyUp(WPARAM wParam, bool isEditorMode) noexcept
void Trace::ZoneWindow::KeyUp(WPARAM wParam) noexcept
{
TraceLoggingWrite(
g_hProvider,
"FancyZones_ZoneWindowKeyUp",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingValue(wParam, "KeyboardValue"),
TraceLoggingBoolean(isEditorMode, "EditorMode"));
TraceLoggingValue(wParam, "KeyboardValue"));
}
void Trace::ZoneWindow::MoveSizeEnd(_In_opt_ winrt::com_ptr<IZoneSet> activeSet) noexcept
@@ -121,8 +107,7 @@ void Trace::ZoneWindow::MoveSizeEnd(_In_opt_ winrt::com_ptr<IZoneSet> activeSet)
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingValue(reinterpret_cast<void*>(activeSet.get()), "ActiveSet"),
TraceLoggingValue(zoneInfo.NumberOfZones, "NumberOfZones"),
TraceLoggingValue(zoneInfo.NumberOfWindows, "NumberOfWindows"),
TraceLoggingValue(static_cast<int>(zoneInfo.Layout), "LayoutKind"));
TraceLoggingValue(zoneInfo.NumberOfWindows, "NumberOfWindows"));
}
void Trace::ZoneWindow::CycleActiveZoneSet(_In_opt_ winrt::com_ptr<IZoneSet> activeSet, InputMode mode) noexcept
@@ -136,29 +121,5 @@ void Trace::ZoneWindow::CycleActiveZoneSet(_In_opt_ winrt::com_ptr<IZoneSet> act
TraceLoggingValue(reinterpret_cast<void*>(activeSet.get()), "ActiveSet"),
TraceLoggingValue(zoneInfo.NumberOfZones, "NumberOfZones"),
TraceLoggingValue(zoneInfo.NumberOfWindows, "NumberOfWindows"),
TraceLoggingValue(static_cast<int>(zoneInfo.Layout), "LayoutKind"),
TraceLoggingValue(static_cast<int>(mode), "InputMode"));
}
void Trace::ZoneWindow::EditorModeActivity::Start() noexcept
{
m_activity = TraceLoggingActivity<g_hProvider, PROJECT_KEYWORD_MEASURE>();
TraceLoggingWriteStart(
m_activity.value(),
"FancyZones_Activity_EditorMode",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance));
}
void Trace::ZoneWindow::EditorModeActivity::Stop(_In_opt_ winrt::com_ptr<IZoneSet> activeSet) noexcept
{
auto const zoneInfo = GetZoneSetInfo(activeSet);
TraceLoggingWriteStop(
m_activity.value(),
"FancyZones_Activity_EditorMode",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingValue(reinterpret_cast<void*>(activeSet.get()), "ActiveSet"),
TraceLoggingValue(zoneInfo.NumberOfZones, "NumberOfZones"),
TraceLoggingValue(zoneInfo.NumberOfWindows, "NumberOfWindows"),
TraceLoggingValue(static_cast<int>(zoneInfo.Layout), "LayoutKind"));
m_activity.reset();
}

View File

@@ -13,7 +13,6 @@ public:
{
public:
static void EnableFancyZones(bool enabled) noexcept;
static void ToggleZoneViewers(bool visible) noexcept;
static void OnKeyDown(DWORD vkCode, bool win, bool control, bool inMoveSize) noexcept;
};
@@ -29,17 +28,8 @@ public:
Mouse
};
static void KeyUp(WPARAM wParam, bool isEditorMode) noexcept;
static void KeyUp(WPARAM wparam) noexcept;
static void MoveSizeEnd(_In_opt_ winrt::com_ptr<IZoneSet> activeSet) noexcept;
static void CycleActiveZoneSet(_In_opt_ winrt::com_ptr<IZoneSet> activeSet, InputMode mode) noexcept;
class EditorModeActivity
{
public:
void Start() noexcept;
void Stop(_In_opt_ winrt::com_ptr<IZoneSet> activeSet) noexcept;
private:
std::optional<TraceLoggingActivity<g_hProvider, PROJECT_KEYWORD_MEASURE>> m_activity{};
};
};
};

View File

@@ -12,30 +12,24 @@ namespace FancyZonesUnitTests
{
GUID zoneSetId{};
CoCreateGuid(&zoneSetId);
constexpr size_t zoneCount = 0;
constexpr WORD layoutId = 0xFFFF;
constexpr int outerPadding = 3;
constexpr int innerPadding = 4;
ZoneSetConfig config(zoneSetId, layoutId, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, zoneCount, outerPadding, innerPadding);
ZoneSetConfig config(zoneSetId, layoutId, Mocks::Monitor(), L"WorkAreaIn");
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
Assert::IsNotNull(&set);
CustomAssert::AreEqual(set->Id(), zoneSetId);
CustomAssert::AreEqual(set->LayoutId(), layoutId);
Assert::IsTrue(set->GetLayout() == ZoneSetLayout::Grid);
Assert::AreEqual(set->GetZones().size(), zoneCount);
Assert::AreEqual(set->GetInnerPadding(), innerPadding);
}
TEST_METHOD(TestAddZone)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn");
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a zone
{
winrt::com_ptr<IZone> zone = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone, false /*front*/);
set->AddZone(zone);
auto zones = set->GetZones();
Assert::IsTrue(zones.size() == 1);
Assert::IsTrue(zones[0] == zone);
@@ -45,7 +39,7 @@ namespace FancyZonesUnitTests
// Add a second zone at the back.
{
winrt::com_ptr<IZone> zone = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone, false /*front*/);
set->AddZone(zone);
auto zones = set->GetZones();
Assert::IsTrue(zones.size() == 2);
Assert::IsTrue(zones[1] == zone);
@@ -53,157 +47,18 @@ namespace FancyZonesUnitTests
}
}
TEST_METHOD(TestAddZoneFront)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a zone.
{
winrt::com_ptr<IZone> zone = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone, false /*front*/);
auto zones = set->GetZones();
Assert::IsTrue(zones.size() == 1);
Assert::IsTrue(zones[0] == zone);
Assert::IsTrue(zone->Id() == 1);
}
// Add a second zone at the front.
{
winrt::com_ptr<IZone> zone = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone, true /*front*/);
auto zones = set->GetZones();
Assert::IsTrue(zones.size() == 2);
Assert::IsTrue(zones[0] == zone);
Assert::IsTrue(zone->Id() == 2);
}
}
TEST_METHOD(TestRemoveZone)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a zone.
winrt::com_ptr<IZone> zone = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone, false /*front*/);
// And remove it.
set->RemoveZone(zone);
Assert::IsTrue(set->GetZones().size() == 0);
}
TEST_METHOD(TestRemoveInvalidZone)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
winrt::com_ptr<IZone> zone = MakeZone({ 0, 0, 100, 100 });
Assert::AreEqual(set->RemoveZone(zone), E_INVALIDARG);
}
TEST_METHOD(TestMoveZoneToFront)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a couple of zones.
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone2 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone1, false /*front*/);
set->AddZone(zone2, false /*front*/);
set->AddZone(zone3, false /*front*/);
// And move it to the back.
set->MoveZoneToFront(zone3);
auto zones = set->GetZones();
Assert::IsTrue(zones.size() == 3);
Assert::IsTrue(zones[0] == zone3);
Assert::IsTrue(zones[1] == zone1);
Assert::IsTrue(zones[2] == zone2);
}
TEST_METHOD(TestMoveZoneToFrontWithInvalidZone)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a couple of zones.
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone2 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone1, false /*front*/);
set->AddZone(zone2, false /*front*/);
set->AddZone(zone3, false /*front*/);
// Create an invalid zone and try to move it.
winrt::com_ptr<IZone> invalidZone = MakeZone({ 0, 0, 100, 100 });
set->MoveZoneToFront(invalidZone);
auto zones = set->GetZones();
Assert::IsTrue(zones.size() == 3);
Assert::IsTrue(zones[0] == zone1);
Assert::IsTrue(zones[1] == zone2);
Assert::IsTrue(zones[2] == zone3);
}
TEST_METHOD(TestMoveZoneToBack)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a couple of zones.
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone2 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone1, false /*front*/);
set->AddZone(zone2, false /*front*/);
set->AddZone(zone3, false /*front*/);
// And move it to the back.
set->MoveZoneToBack(zone1);
auto zones = set->GetZones();
Assert::IsTrue(zones.size() == 3);
Assert::IsTrue(zones[0] == zone2);
Assert::IsTrue(zones[1] == zone3);
Assert::IsTrue(zones[2] == zone1);
}
TEST_METHOD(TestMoveZoneToBackWithInvalidZone)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a couple of zones.
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone2 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone1, false /*front*/);
set->AddZone(zone2, false /*front*/);
set->AddZone(zone3, false /*front*/);
// Create an invalid zone and try to move it.
winrt::com_ptr<IZone> invalidZone = MakeZone({ 0, 0, 100, 100 });
set->MoveZoneToBack(invalidZone);
auto zones = set->GetZones();
Assert::IsTrue(zones.size() == 3);
Assert::IsTrue(zones[0] == zone1);
Assert::IsTrue(zones[1] == zone2);
Assert::IsTrue(zones[2] == zone3);
}
TEST_METHOD(TestMoveWindowIntoZoneByIndex)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn");
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a couple of zones.
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone2 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone1, false /*front*/);
set->AddZone(zone2, false /*front*/);
set->AddZone(zone3, false /*front*/);
set->AddZone(zone1);
set->AddZone(zone2);
set->AddZone(zone3);
HWND window = Mocks::Window();
set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1);
@@ -214,7 +69,7 @@ namespace FancyZonesUnitTests
TEST_METHOD(TestMoveWindowIntoZoneByIndexWithNoZones)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn");
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a couple of zones.
@@ -224,16 +79,16 @@ namespace FancyZonesUnitTests
TEST_METHOD(TestMoveWindowIntoZoneByIndexWithInvalidIndex)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn");
winrt::com_ptr<IZoneSet> set = MakeZoneSet(config);
// Add a couple of zones.
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone2 = MakeZone({ 0, 0, 100, 100 });
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone1, false /*front*/);
set->AddZone(zone2, false /*front*/);
set->AddZone(zone3, false /*front*/);
set->AddZone(zone1);
set->AddZone(zone2);
set->AddZone(zone3);
HWND window = Mocks::Window();
set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 100);
@@ -253,16 +108,16 @@ namespace FancyZonesUnitTests
TEST_METHOD_INITIALIZE(Initialize)
{
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn", ZoneSetLayout::Grid, 0, 3, 4);
ZoneSetConfig config({}, 0xFFFF, Mocks::Monitor(), L"WorkAreaIn");
set = MakeZoneSet(config);
// Add a couple of zones.
zone1 = MakeZone({ 0, 0, 100, 100 });
zone2 = MakeZone({ 0, 0, 100, 100 });
zone3 = MakeZone({ 0, 0, 100, 100 });
set->AddZone(zone1, false /*front*/);
set->AddZone(zone2, false /*front*/);
set->AddZone(zone3, false /*front*/);
set->AddZone(zone1);
set->AddZone(zone2);
set->AddZone(zone3);
}
TEST_METHOD(MoveWindowIntoZoneByDirectionRightNoZones)

View File

@@ -19,6 +19,8 @@ public:
virtual void disable() = 0;
virtual bool is_enabled() = 0;
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) = 0;
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) = 0;
virtual void signal_system_menu_action(const wchar_t* name) = 0;
virtual void destroy() = 0;
};
@@ -43,6 +45,8 @@ and destroy():
- [`set_config()`](#set_config) to set settings after they have been edited in the Settings editor,
- [`call_custom_action()`](#call_custom_action) when the user selects a custom action in the Settings editor,
- [`signal_event()`](#signal_event) to send an event the PowerToy registered to.
- [`register_system_menu_helper()`](#register_system_menu_helper) to pass object, responsible for handling customized system menus, to module.
- [`signal_system_menu_action()`](#signal_system_menu_action) to send an event when action is taken on system menu item.
When terminating, the runner will:
- call [`disable()`](#disable),
@@ -313,6 +317,25 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
}
```
### register_system_menu_helper
```cpp
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) = 0;
```
Register helper class to handle all system menu items related actions. Creation, deletion
and all other actions taken on system menu item will be handled by provided class.
Module will be informed when action is taken on any item created on request of the module.
### signal_system_menu_action
```cpp
virtual void signal_system_menu_action(const wchar_t* name) = 0;
```
Runner invokes this API when action is taken on item created on request from the module.
Item name is passed as an argument, so that module can distinguish between different menu items.
#### destroy
```cpp
@@ -328,11 +351,59 @@ Sample code from [`the example PowerToy`](/src/modules/example_powertoy/dllmain.
}
```
### Powertoys system menu helper interface
Interface for helper class responsible for handling all system menu related actions.
```cpp
class PowertoySystemMenuIface {
public:
struct ItemInfo {
std::wstring name{};
bool enable{ false };
bool checkBox{ false };
};
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) = 0;
virtual void ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) = 0;
};
```
### ItemInfo
```cpp
struct ItemInfo {
std::wstring name{};
bool enable{ false };
bool checkBox{ false };
};
```
Structure containing all relevant information for system menu item: name (and hotkey if available), item
status at creation (enabled/disabled) and whether check box will appear next to item name when action is taken.
### SetConfiguration
```cpp
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) = 0;
```
Module should use this interface to inform system menu helper class which custom system menu items to create.
### ProcessSelectedItem
```cpp
virtual void ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) = 0;
```
Process action taken on specific system menu item.
## Code organization
#### [`powertoy_module_interface.h`](./powertoy_module_interface.h)
Contains the PowerToys interface definition.
### [`powertoy_system_menu.h`](./powertoy_system_module.h)
Contains the PowerToys system menu helper interface definition.
#### [`lowlevel_keyboard_event_data.h`](./lowlevel_keyboard_event_data.h)
Contains the `LowlevelKeyboardEvent` structure that's passed to `signal_event` for `ll_keyboard` events.

View File

@@ -28,6 +28,8 @@
- unload the DLL.
*/
class PowertoySystemMenuIface;
class PowertoyModuleIface {
public:
/* Returns the name of the PowerToy, this will be cached by the runner. */
@@ -63,6 +65,12 @@ public:
* win_hook_event: see win_hook_event_data.h
*/
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) = 0;
/* Register helper class to handle system menu items related actions. */
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) = 0;
/* Handle action on system menu item. */
virtual void signal_system_menu_action(const wchar_t* name) = 0;
/* Destroy the PowerToy and free all memory. */
virtual void destroy() = 0;
};

View File

@@ -0,0 +1,22 @@
#pragma once
#include <string>
class PowertoyModuleIface;
class PowertoySystemMenuIface {
public:
struct ItemInfo {
std::wstring name{};
bool enable{ false };
bool checkBox{ false };
};
/*
* Set configuration of system menu items for specific powertoy module. Configuration
* parameters include item name (and hotkey), item status at creation (enabled/disabled)
* and whether check box will appear next to item name when action is taken.
*/
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) = 0;
/* Process action on specific system menu item. */
virtual void ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) = 0;
};

View File

@@ -4,6 +4,8 @@
#include <PowerRenameItem.h>
#include <PowerRenameManager.h>
#include <trace.h>
#include <Helpers.h>
#include <Settings.h>
#include "resource.h"
extern HINSTANCE g_hInst;
@@ -14,24 +16,6 @@ struct InvokeStruct
IStream* pstrm;
};
const wchar_t powerRenameRegPath[] = L"Software\\Microsoft\\PowerRename";
const wchar_t powerRenameRegEnabledName[] = L"Enabled";
bool CPowerRenameMenu::IsEnabled()
{
DWORD type = REG_DWORD;
DWORD dwEnabled = 0;
DWORD cb = sizeof(dwEnabled);
SHGetValue(HKEY_CURRENT_USER, powerRenameRegPath, powerRenameRegEnabledName, &type, &dwEnabled, &cb);
return (dwEnabled == 0) ? false : true;
}
bool CPowerRenameMenu::SetEnabled(_In_ bool enabled)
{
DWORD dwEnabled = enabled ? 1 : 0;
return SUCCEEDED(HRESULT_FROM_WIN32(SHSetValueW(HKEY_CURRENT_USER, powerRenameRegPath, powerRenameRegEnabledName, REG_DWORD, &dwEnabled, sizeof(dwEnabled))));
}
CPowerRenameMenu::CPowerRenameMenu()
{
DllAddRef();
@@ -40,6 +24,7 @@ CPowerRenameMenu::CPowerRenameMenu()
CPowerRenameMenu::~CPowerRenameMenu()
{
m_spdo = nullptr;
DeleteObject(m_hbmpIcon);
DllRelease();
}
@@ -60,7 +45,7 @@ HRESULT CPowerRenameMenu::s_CreateInstance(_In_opt_ IUnknown*, _In_ REFIID riid,
HRESULT CPowerRenameMenu::Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObject *pdtobj, HKEY)
{
// Check if we have disabled ourselves
if (!IsEnabled())
if (!CSettings::GetEnabled())
return E_FAIL;
// Cache the data object to be used later
@@ -72,7 +57,11 @@ HRESULT CPowerRenameMenu::Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObjec
HRESULT CPowerRenameMenu::QueryContextMenu(HMENU hMenu, UINT index, UINT uIDFirst, UINT, UINT uFlags)
{
// Check if we have disabled ourselves
if (!IsEnabled())
if (!CSettings::GetEnabled())
return E_FAIL;
// Check if we should only be on the extended context menu
if (CSettings::GetExtendedContextMenuOnly() && (!(uFlags & CMF_EXTENDEDVERBS)))
return E_FAIL;
HRESULT hr = E_UNEXPECTED;
@@ -80,8 +69,38 @@ HRESULT CPowerRenameMenu::QueryContextMenu(HMENU hMenu, UINT index, UINT uIDFirs
{
wchar_t menuName[64] = { 0 };
LoadString(g_hInst, IDS_POWERRENAME, menuName, ARRAYSIZE(menuName));
InsertMenu(hMenu, index, MF_STRING | MF_BYPOSITION, uIDFirst++, menuName);
hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 1);
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
mii.wID = uIDFirst++;
mii.fType = MFT_STRING;
mii.dwTypeData = (PWSTR)menuName;
mii.fState = MFS_ENABLED;
if (CSettings::GetShowIconOnMenu())
{
HICON hIcon = (HICON)LoadImage(g_hInst, MAKEINTRESOURCE(IDI_RENAME), IMAGE_ICON, 16, 16, 0);
if (hIcon)
{
mii.fMask |= MIIM_BITMAP;
if (m_hbmpIcon == NULL)
{
m_hbmpIcon = CreateBitmapFromIcon(hIcon);
}
mii.hbmpItem = m_hbmpIcon;
DestroyIcon(hIcon);
}
}
if (!InsertMenuItem(hMenu, index, TRUE, &mii))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 1);
}
}
return hr;
@@ -91,7 +110,7 @@ HRESULT CPowerRenameMenu::InvokeCommand(_In_ LPCMINVOKECOMMANDINFO pici)
{
HRESULT hr = E_FAIL;
if (IsEnabled() &
if (CSettings::GetEnabled() &&
(IS_INTRESOURCE(pici->lpVerb)) &&
(LOWORD(pici->lpVerb) == 0))
{
@@ -129,7 +148,7 @@ DWORD WINAPI CPowerRenameMenu::s_PowerRenameUIThreadProc(_In_ void* pData)
HRESULT hr = CoGetInterfaceAndReleaseStream(pInvokeData->pstrm, IID_PPV_ARGS(&spdo));
if (SUCCEEDED(hr))
{
// Create the smart rename manager
// Create the rename manager
CComPtr<IPowerRenameManager> spsrm;
hr = CPowerRenameManager::s_CreateInstance(&spsrm);
if (SUCCEEDED(hr))
@@ -140,10 +159,10 @@ DWORD WINAPI CPowerRenameMenu::s_PowerRenameUIThreadProc(_In_ void* pData)
if (SUCCEEDED(hr))
{
// Pass the factory to the manager
hr = spsrm->put_smartRenameItemFactory(spsrif);
hr = spsrm->put_renameItemFactory(spsrif);
if (SUCCEEDED(hr))
{
// Create the smart rename UI instance and pass the smart rename manager
// Create the rename UI instance and pass the rename manager
CComPtr<IPowerRenameUI> spsrui;
hr = CPowerRenameUI::s_CreateInstance(spsrm, spdo, false, &spsrui);
if (SUCCEEDED(hr))

View File

@@ -56,6 +56,7 @@ private:
~CPowerRenameMenu();
long m_refCount = 1;
HBITMAP m_hbmpIcon = NULL;
CComPtr<IDataObject> m_spdo;
};

View File

@@ -1,190 +1,191 @@
<?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|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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>{B25AC7A5-FB9F-4789-B392-D5C85E948670}</ProjectGuid>
<RootNamespace>PowerRenameExt</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</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|Win32'">
<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|Win32'">
<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)'=='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|Win32'">
<TargetExt>.dll</TargetExt>
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<TargetName>$(ProjectName)</TargetName>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<TargetName>$(ProjectName)</TargetName>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<TargetName>$(ProjectName)</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<TargetName>$(ProjectName)</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
<ClInclude Include="PowerRenameExt.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameExt.rc" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="PowerRenameExt.cpp" />
<ClCompile Include="stdafx.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="PowerRenameExt.def" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\common.vcxproj">
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<?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|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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>{B25AC7A5-FB9F-4789-B392-D5C85E948670}</ProjectGuid>
<RootNamespace>PowerRenameExt</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</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|Win32'">
<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|Win32'">
<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)'=='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|Win32'">
<TargetExt>.dll</TargetExt>
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<TargetName>$(ProjectName)</TargetName>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<TargetName>$(ProjectName)</TargetName>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<TargetName>$(ProjectName)</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>..\lib\;..\ui\;$(IncludePath)</IncludePath>
<TargetName>$(ProjectName)</TargetName>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
<LibraryPath>$(SolutionDir)$(Platform)\$(Configuration)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameLib.lib;$(SolutionDir)$(Platform)\$(Configuration)\PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(SolutionDir)$(Platform)\$(Configuration)\..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>PowerRenameExt.def</ModuleDefinitionFile>
<DelayLoadDLLs>gdi32.dll;advapi32.dll;shell32.dll;ole32.dll;shlwapi.dll;oleaut32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
<ClInclude Include="PowerRenameExt.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameExt.rc" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="PowerRenameExt.cpp" />
<ClCompile Include="stdafx.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="PowerRenameExt.def" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\common.vcxproj">
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,6 +1,7 @@
#include "stdafx.h"
#include "PowerRenameExt.h"
#include <interface/powertoy_module_interface.h>
#include <settings.h>
#include <trace.h>
#include <common/settings_objects.h>
@@ -9,10 +10,10 @@ HINSTANCE g_hInst = 0;
extern "C" IMAGE_DOS_HEADER __ImageBase;
class CSmartRenameClassFactory : public IClassFactory
class CPowerRenameClassFactory : public IClassFactory
{
public:
CSmartRenameClassFactory(_In_ REFCLSID clsid) :
CPowerRenameClassFactory(_In_ REFCLSID clsid) :
m_refCount(1),
m_clsid(clsid)
{
@@ -24,7 +25,7 @@ public:
{
static const QITAB qit[] =
{
QITABENT(CSmartRenameClassFactory, IClassFactory),
QITABENT(CPowerRenameClassFactory, IClassFactory),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
@@ -82,7 +83,7 @@ public:
}
private:
~CSmartRenameClassFactory()
~CPowerRenameClassFactory()
{
DllRelease();
}
@@ -122,7 +123,7 @@ STDAPI DllGetClassObject(_In_ REFCLSID clsid, _In_ REFIID riid, _Outptr_ void **
{
*ppv = NULL;
HRESULT hr = E_OUTOFMEMORY;
CSmartRenameClassFactory *pClassFactory = new CSmartRenameClassFactory(clsid);
CPowerRenameClassFactory *pClassFactory = new CPowerRenameClassFactory(clsid);
if (pClassFactory)
{
hr = pClassFactory->QueryInterface(riid, ppv);
@@ -206,6 +207,39 @@ public:
// Link to the GitHub PowerRename sub-page
settings.set_overview_link(L"https://github.com/microsoft/PowerToys/tree/master/src/modules/powerrename");
settings.add_bool_toogle(
L"bool_persist_input",
L"Restore search, replace and flags values on launch from previous run.",
CSettings::GetPersistState()
);
settings.add_bool_toogle(
L"bool_mru_enabled",
L"Enable autocomplete and autosuggest of recently used inputs for search and replace values.",
CSettings::GetMRUEnabled()
);
settings.add_int_spinner(
L"int_max_mru_size",
L"Maximum number of items to show in recently used list for autocomplete dropdown.",
CSettings::GetMaxMRUSize(),
0,
20,
1
);
settings.add_bool_toogle(
L"bool_show_icon_on_menu",
L"Show icon on context menu.",
CSettings::GetShowIconOnMenu()
);
settings.add_bool_toogle(
L"bool_show_extended_menu",
L"Only show the PowerRename menu item on the extended context menu (SHIFT + Right-click).",
CSettings::GetExtendedContextMenuOnly()
);
return settings.serialize_to_buffer(buffer, buffer_size);
}
@@ -213,6 +247,20 @@ public:
// This is called when the user hits Save on the settings page.
virtual void set_config(PCWSTR config) override
{
try {
// Parse the input JSON string.
PowerToysSettings::PowerToyValues values =
PowerToysSettings::PowerToyValues::from_json_string(config);
CSettings::SetPersistState(values.get_bool_value(L"bool_persist_input"));
CSettings::SetMRUEnabled(values.get_bool_value(L"bool_mru_enabled"));
CSettings::SetMaxMRUSize(values.get_int_value(L"int_max_mru_size"));
CSettings::SetShowIconOnMenu(values.get_bool_value(L"bool_show_icon_on_menu"));
CSettings::SetExtendedContextMenuOnly(values.get_bool_value(L"bool_show_extended_menu"));
}
catch (std::exception) {
// Improper JSON.
}
}
// Signal from the Settings editor to call a custom action.
@@ -227,6 +275,9 @@ public:
return 0;
}
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override { }
virtual void signal_system_menu_action(const wchar_t* name) override { }
// Destroy the powertoy and free memory
virtual void destroy() override
{
@@ -235,13 +286,13 @@ public:
void init_settings()
{
m_enabled = CPowerRenameMenu::IsEnabled();
m_enabled = CSettings::GetEnabled();
Trace::EnablePowerRename(m_enabled);
}
void save_settings()
{
CPowerRenameMenu::SetEnabled(m_enabled);
CSettings::SetEnabled(m_enabled);
Trace::EnablePowerRename(m_enabled);
}

View File

@@ -1,4 +1,5 @@
#define IDS_POWERRENAME 801
#define IDI_RENAME 132
// Next default values for new objects
//

View File

@@ -25,6 +25,71 @@ HRESULT GetIconIndexFromPath(_In_ PCWSTR path, _Out_ int* index)
return hr;
}
HBITMAP CreateBitmapFromIcon(_In_ HICON hIcon, _In_opt_ UINT width, _In_opt_ UINT height)
{
HBITMAP hBitmapResult = NULL;
// Create compatible DC
HDC hDC = CreateCompatibleDC(NULL);
if (hDC != NULL)
{
// Get bitmap rectangle size
RECT rc = { 0 };
rc.left = 0;
rc.right = (width != 0) ? width : GetSystemMetrics(SM_CXSMICON);
rc.top = 0;
rc.bottom = (height != 0) ? height : GetSystemMetrics(SM_CYSMICON);
// Create bitmap compatible with DC
BITMAPINFO BitmapInfo;
ZeroMemory(&BitmapInfo, sizeof(BITMAPINFO));
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfo.bmiHeader.biWidth = rc.right;
BitmapInfo.bmiHeader.biHeight = rc.bottom;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
HDC hDCBitmap = GetDC(NULL);
HBITMAP hBitmap = CreateDIBSection(hDCBitmap, &BitmapInfo, DIB_RGB_COLORS, NULL, NULL, 0);
ReleaseDC(NULL, hDCBitmap);
if (hBitmap != NULL)
{
// Select bitmap into DC
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap);
if (hBitmapOld != NULL)
{
// Draw icon into DC
if (DrawIconEx(hDC, 0, 0, hIcon, rc.right, rc.bottom, 0, NULL, DI_NORMAL))
{
// Restore original bitmap in DC
hBitmapResult = (HBITMAP)SelectObject(hDC, hBitmapOld);
hBitmapOld = NULL;
hBitmap = NULL;
}
if (hBitmapOld != NULL)
{
SelectObject(hDC, hBitmapOld);
}
}
if (hBitmap != NULL)
{
DeleteObject(hBitmap);
}
}
DeleteDC(hDC);
}
return hBitmapResult;
}
HRESULT _ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ IPowerRenameManager* psrm, _In_ int depth = 0)
{
HRESULT hr = E_INVALIDARG;
@@ -40,7 +105,7 @@ HRESULT _ParseEnumItems(_In_ IEnumShellItems* pesi, _In_ IPowerRenameManager* ps
while ((S_OK == pesi->Next(1, &spsi, &celtFetched)) && (SUCCEEDED(hr)))
{
CComPtr<IPowerRenameItemFactory> spsrif;
hr = psrm->get_smartRenameItemFactory(&spsrif);
hr = psrm->get_renameItemFactory(&spsrif);
if (SUCCEEDED(hr))
{
CComPtr<IPowerRenameItem> spNewItem;

View File

@@ -1,8 +1,8 @@
#pragma once
#include "stdafx.h"
HRESULT EnumerateDataObject(_In_ IDataObject* pdo, _In_ IPowerRenameManager* psrm);
HRESULT GetIconIndexFromPath(_In_ PCWSTR path, _Out_ int* index);
HBITMAP CreateBitmapFromIcon(_In_ HICON hIcon, _In_opt_ UINT width = 0, _In_opt_ UINT height = 0);
HWND CreateMsgWindow(_In_ HINSTANCE hInst, _In_ WNDPROC pfnWndProc, _In_ void* p);
BOOL GetEnumeratedFileName(
__out_ecount(cchMax) PWSTR pszUniqueName, UINT cchMax,

View File

@@ -93,10 +93,10 @@ public:
IFACEMETHOD(GetRenameItemCount)(_Out_ UINT* count) = 0;
IFACEMETHOD(get_flags)(_Out_ DWORD* flags) = 0;
IFACEMETHOD(put_flags)(_In_ DWORD flags) = 0;
IFACEMETHOD(get_smartRenameRegEx)(_COM_Outptr_ IPowerRenameRegEx** ppRegEx) = 0;
IFACEMETHOD(put_smartRenameRegEx)(_In_ IPowerRenameRegEx* pRegEx) = 0;
IFACEMETHOD(get_smartRenameItemFactory)(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory) = 0;
IFACEMETHOD(put_smartRenameItemFactory)(_In_ IPowerRenameItemFactory* pItemFactory) = 0;
IFACEMETHOD(get_renameRegEx)(_COM_Outptr_ IPowerRenameRegEx** ppRegEx) = 0;
IFACEMETHOD(put_renameRegEx)(_In_ IPowerRenameRegEx* pRegEx) = 0;
IFACEMETHOD(get_renameItemFactory)(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory) = 0;
IFACEMETHOD(put_renameItemFactory)(_In_ IPowerRenameItemFactory* pItemFactory) = 0;
};
interface __declspec(uuid("E6679DEB-460D-42C1-A7A8-E25897061C99")) IPowerRenameUI : public IUnknown
@@ -107,3 +107,9 @@ public:
IFACEMETHOD(Update)() = 0;
};
interface __declspec(uuid("04AAFABE-B76E-4E13-993A-B5941F52B139")) IPowerRenameMRU : public IUnknown
{
public:
IFACEMETHOD(AddMRUString)(_In_ PCWSTR entry) = 0;
};

View File

@@ -1,171 +1,173 @@
<?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|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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>{51920F1F-C28C-4ADF-8660-4238766796C2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRenameLib</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<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|Win32'">
<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|Win32'">
<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)'=='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|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Helpers.h" />
<ClInclude Include="PowerRenameItem.h" />
<ClInclude Include="PowerRenameInterfaces.h" />
<ClInclude Include="PowerRenameManager.h" />
<ClInclude Include="PowerRenameRegEx.h" />
<ClInclude Include="srwlock.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Helpers.cpp" />
<ClCompile Include="PowerRenameItem.cpp" />
<ClCompile Include="PowerRenameManager.cpp" />
<ClCompile Include="PowerRenameRegEx.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="trace.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<?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|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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>{51920F1F-C28C-4ADF-8660-4238766796C2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRenameLib</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<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|Win32'">
<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|Win32'">
<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)'=='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|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Helpers.h" />
<ClInclude Include="PowerRenameItem.h" />
<ClInclude Include="PowerRenameInterfaces.h" />
<ClInclude Include="PowerRenameManager.h" />
<ClInclude Include="PowerRenameRegEx.h" />
<ClInclude Include="Settings.h" />
<ClInclude Include="srwlock.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Helpers.cpp" />
<ClCompile Include="PowerRenameItem.cpp" />
<ClCompile Include="PowerRenameManager.cpp" />
<ClCompile Include="PowerRenameRegEx.cpp" />
<ClCompile Include="Settings.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="trace.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -44,11 +44,11 @@ IFACEMETHODIMP CPowerRenameManager::Advise(_In_ IPowerRenameManagerEvents* renam
{
CSRWExclusiveAutoLock lock(&m_lockEvents);
m_cookie++;
SMART_RENAME_MGR_EVENT srme;
RENAME_MGR_EVENT srme;
srme.cookie = m_cookie;
srme.pEvents = renameOpEvents;
renameOpEvents->AddRef();
m_PowerRenameManagerEvents.push_back(srme);
m_powerRenameManagerEvents.push_back(srme);
*cookie = m_cookie;
@@ -60,16 +60,16 @@ IFACEMETHODIMP CPowerRenameManager::UnAdvise(_In_ DWORD cookie)
HRESULT hr = E_FAIL;
CSRWExclusiveAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (std::vector<RENAME_MGR_EVENT>::iterator it = m_powerRenameManagerEvents.begin(); it != m_powerRenameManagerEvents.end(); ++it)
{
if (it.cookie == cookie)
if (it->cookie == cookie)
{
hr = S_OK;
it.cookie = 0;
if (it.pEvents)
it->cookie = 0;
if (it->pEvents)
{
it.pEvents->Release();
it.pEvents = nullptr;
it->pEvents->Release();
it->pEvents = nullptr;
}
break;
}
@@ -117,9 +117,9 @@ IFACEMETHODIMP CPowerRenameManager::AddItem(_In_ IPowerRenameItem* pItem)
int id = 0;
pItem->get_id(&id);
// Verify the item isn't already added
if (m_smartRenameItems.find(id) == m_smartRenameItems.end())
if (m_renameItems.find(id) == m_renameItems.end())
{
m_smartRenameItems[id] = pItem;
m_renameItems[id] = pItem;
pItem->AddRef();
hr = S_OK;
}
@@ -138,9 +138,9 @@ IFACEMETHODIMP CPowerRenameManager::GetItemByIndex(_In_ UINT index, _COM_Outptr_
*ppItem = nullptr;
CSRWSharedAutoLock lock(&m_lockItems);
HRESULT hr = E_FAIL;
if (index < m_smartRenameItems.size())
if (index < m_renameItems.size())
{
std::map<int, IPowerRenameItem*>::iterator it = m_smartRenameItems.begin();
std::map<int, IPowerRenameItem*>::iterator it = m_renameItems.begin();
std::advance(it, index);
*ppItem = it->second;
(*ppItem)->AddRef();
@@ -157,10 +157,10 @@ IFACEMETHODIMP CPowerRenameManager::GetItemById(_In_ int id, _COM_Outptr_ IPower
CSRWSharedAutoLock lock(&m_lockItems);
HRESULT hr = E_FAIL;
std::map<int, IPowerRenameItem*>::iterator it;
it = m_smartRenameItems.find(id);
if (it != m_smartRenameItems.end())
it = m_renameItems.find(id);
if (it != m_renameItems.end())
{
*ppItem = m_smartRenameItems[id];
*ppItem = m_renameItems[id];
(*ppItem)->AddRef();
hr = S_OK;
}
@@ -171,7 +171,7 @@ IFACEMETHODIMP CPowerRenameManager::GetItemById(_In_ int id, _COM_Outptr_ IPower
IFACEMETHODIMP CPowerRenameManager::GetItemCount(_Out_ UINT* count)
{
CSRWSharedAutoLock lock(&m_lockItems);
*count = static_cast<UINT>(m_smartRenameItems.size());
*count = static_cast<UINT>(m_renameItems.size());
return S_OK;
}
@@ -180,7 +180,7 @@ IFACEMETHODIMP CPowerRenameManager::GetSelectedItemCount(_Out_ UINT* count)
*count = 0;
CSRWSharedAutoLock lock(&m_lockItems);
for (auto it : m_smartRenameItems)
for (auto it : m_renameItems)
{
IPowerRenameItem* pItem = it.second;
bool selected = false;
@@ -198,7 +198,7 @@ IFACEMETHODIMP CPowerRenameManager::GetRenameItemCount(_Out_ UINT* count)
*count = 0;
CSRWSharedAutoLock lock(&m_lockItems);
for (auto it : m_smartRenameItems)
for (auto it : m_renameItems)
{
IPowerRenameItem* pItem = it.second;
bool shouldRename = false;
@@ -229,7 +229,7 @@ IFACEMETHODIMP CPowerRenameManager::put_flags(_In_ DWORD flags)
return S_OK;
}
IFACEMETHODIMP CPowerRenameManager::get_smartRenameRegEx(_COM_Outptr_ IPowerRenameRegEx** ppRegEx)
IFACEMETHODIMP CPowerRenameManager::get_renameRegEx(_COM_Outptr_ IPowerRenameRegEx** ppRegEx)
{
*ppRegEx = nullptr;
HRESULT hr = _EnsureRegEx();
@@ -241,14 +241,14 @@ IFACEMETHODIMP CPowerRenameManager::get_smartRenameRegEx(_COM_Outptr_ IPowerRena
return hr;
}
IFACEMETHODIMP CPowerRenameManager::put_smartRenameRegEx(_In_ IPowerRenameRegEx* pRegEx)
IFACEMETHODIMP CPowerRenameManager::put_renameRegEx(_In_ IPowerRenameRegEx* pRegEx)
{
_ClearRegEx();
m_spRegEx = pRegEx;
return S_OK;
}
IFACEMETHODIMP CPowerRenameManager::get_smartRenameItemFactory(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory)
IFACEMETHODIMP CPowerRenameManager::get_renameItemFactory(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory)
{
*ppItemFactory = nullptr;
HRESULT hr = E_FAIL;
@@ -261,7 +261,7 @@ IFACEMETHODIMP CPowerRenameManager::get_smartRenameItemFactory(_COM_Outptr_ IPow
return hr;
}
IFACEMETHODIMP CPowerRenameManager::put_smartRenameItemFactory(_In_ IPowerRenameItemFactory* pItemFactory)
IFACEMETHODIMP CPowerRenameManager::put_renameItemFactory(_In_ IPowerRenameItemFactory* pItemFactory)
{
m_spItemFactory = pItemFactory;
return S_OK;
@@ -281,7 +281,7 @@ IFACEMETHODIMP CPowerRenameManager::OnReplaceTermChanged(_In_ PCWSTR /*replaceTe
IFACEMETHODIMP CPowerRenameManager::OnFlagsChanged(_In_ DWORD flags)
{
// Flags were updated in the smart rename regex. Update our preview.
// Flags were updated in the rename regex. Update our preview.
m_flags = flags;
_PerformRegExRename();
return S_OK;
@@ -330,7 +330,7 @@ HRESULT CPowerRenameManager::_Init()
// Custom messages for worker threads
enum
{
SRM_REGEX_ITEM_UPDATED = (WM_APP + 1), // Single smart rename item processed by regex worker thread
SRM_REGEX_ITEM_UPDATED = (WM_APP + 1), // Single rename item processed by regex worker thread
SRM_REGEX_STARTED, // RegEx operation was started
SRM_REGEX_CANCELED, // Regex operation was canceled
SRM_REGEX_COMPLETE, // Regex worker thread completed
@@ -546,7 +546,7 @@ DWORD WINAPI CPowerRenameManager::s_fileOpWorkerThread(_In_ void* pv)
if (WaitForSingleObject(pwtd->startEvent, INFINITE) == WAIT_OBJECT_0)
{
CComPtr<IPowerRenameRegEx> spRenameRegEx;
if (SUCCEEDED(pwtd->spsrm->get_smartRenameRegEx(&spRenameRegEx)))
if (SUCCEEDED(pwtd->spsrm->get_renameRegEx(&spRenameRegEx)))
{
// Create IFileOperation interface
CComPtr<IFileOperation> spFileOp;
@@ -557,24 +557,45 @@ DWORD WINAPI CPowerRenameManager::s_fileOpWorkerThread(_In_ void* pv)
UINT itemCount = 0;
pwtd->spsrm->GetItemCount(&itemCount);
// Add each rename operation
for (UINT u = 0; u <= itemCount; u++)
// We add the items to the operation in depth-first order. This allows child items to be
// renamed before parent items.
// Creating a vector of vectors of items of the same depth
std::vector<std::vector<UINT>> matrix(itemCount);
for (UINT u = 0; u < itemCount; u++)
{
CComPtr<IPowerRenameItem> spItem;
if (SUCCEEDED(pwtd->spsrm->GetItemByIndex(u, &spItem)))
{
bool shouldRename = false;
if (SUCCEEDED(spItem->ShouldRenameItem(flags, &shouldRename)) && shouldRename)
UINT depth = 0;
spItem->get_depth(&depth);
matrix[depth].push_back(u);
}
}
// From the greatest depth first, add all items of that depth to the operation
for (LONG v = itemCount - 1; v >= 0; v--)
{
for (auto it : matrix[v])
{
CComPtr<IPowerRenameItem> spItem;
if (SUCCEEDED(pwtd->spsrm->GetItemByIndex(it, &spItem)))
{
PWSTR newName = nullptr;
if (SUCCEEDED(spItem->get_newName(&newName)))
bool shouldRename = false;
if (SUCCEEDED(spItem->ShouldRenameItem(flags, &shouldRename)) && shouldRename)
{
CComPtr<IShellItem> spShellItem;
if (SUCCEEDED(spItem->get_shellItem(&spShellItem)))
PWSTR newName = nullptr;
if (SUCCEEDED(spItem->get_newName(&newName)))
{
spFileOp->RenameItem(spShellItem, newName, nullptr);
CComPtr<IShellItem> spShellItem;
if (SUCCEEDED(spItem->get_shellItem(&spShellItem)))
{
spFileOp->RenameItem(spShellItem, newName, nullptr);
}
CoTaskMemFree(newName);
}
CoTaskMemFree(newName);
}
}
}
@@ -674,7 +695,7 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
if (WaitForSingleObject(pwtd->startEvent, INFINITE) == WAIT_OBJECT_0)
{
CComPtr<IPowerRenameRegEx> spRenameRegEx;
if (SUCCEEDED(pwtd->spsrm->get_smartRenameRegEx(&spRenameRegEx)))
if (SUCCEEDED(pwtd->spsrm->get_renameRegEx(&spRenameRegEx)))
{
DWORD flags = 0;
spRenameRegEx->get_flags(&flags);
@@ -900,7 +921,7 @@ void CPowerRenameManager::_OnItemAdded(_In_ IPowerRenameItem* renameItem)
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
@@ -913,7 +934,7 @@ void CPowerRenameManager::_OnUpdate(_In_ IPowerRenameItem* renameItem)
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
@@ -926,7 +947,7 @@ void CPowerRenameManager::_OnError(_In_ IPowerRenameItem* renameItem)
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
@@ -939,7 +960,7 @@ void CPowerRenameManager::_OnRegExStarted(_In_ DWORD threadId)
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
@@ -952,7 +973,7 @@ void CPowerRenameManager::_OnRegExCanceled(_In_ DWORD threadId)
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
@@ -965,7 +986,7 @@ void CPowerRenameManager::_OnRegExCompleted(_In_ DWORD threadId)
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
@@ -978,7 +999,7 @@ void CPowerRenameManager::_OnRenameStarted()
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
@@ -991,7 +1012,7 @@ void CPowerRenameManager::_OnRenameCompleted()
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_PowerRenameManagerEvents)
for (auto it : m_powerRenameManagerEvents)
{
if (it.pEvents)
{
@@ -1005,31 +1026,35 @@ void CPowerRenameManager::_ClearEventHandlers()
CSRWExclusiveAutoLock lock(&m_lockEvents);
// Cleanup event handlers
for (auto it : m_PowerRenameManagerEvents)
for (std::vector<RENAME_MGR_EVENT>::iterator it = m_powerRenameManagerEvents.begin(); it != m_powerRenameManagerEvents.end(); ++it)
{
it.cookie = 0;
if (it.pEvents)
it->cookie = 0;
if (it->pEvents)
{
it.pEvents->Release();
it.pEvents = nullptr;
it->pEvents->Release();
it->pEvents = nullptr;
}
}
m_PowerRenameManagerEvents.clear();
m_powerRenameManagerEvents.clear();
}
void CPowerRenameManager::_ClearPowerRenameItems()
{
CSRWExclusiveAutoLock lock(&m_lockItems);
// Cleanup smart rename items
for (auto it : m_smartRenameItems)
// Cleanup rename items
for (std::map<int, IPowerRenameItem*>::iterator it = m_renameItems.begin(); it != m_renameItems.end(); ++it)
{
IPowerRenameItem* pItem = it.second;
pItem->Release();
IPowerRenameItem* pItem = it->second;
if (pItem)
{
pItem->Release();
it->second = nullptr;
}
}
m_smartRenameItems.clear();
m_renameItems.clear();
}
void CPowerRenameManager::_Cleanup()

View File

@@ -29,10 +29,10 @@ public:
IFACEMETHODIMP GetRenameItemCount(_Out_ UINT* count);
IFACEMETHODIMP get_flags(_Out_ DWORD* flags);
IFACEMETHODIMP put_flags(_In_ DWORD flags);
IFACEMETHODIMP get_smartRenameRegEx(_COM_Outptr_ IPowerRenameRegEx** ppRegEx);
IFACEMETHODIMP put_smartRenameRegEx(_In_ IPowerRenameRegEx* pRegEx);
IFACEMETHODIMP get_smartRenameItemFactory(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory);
IFACEMETHODIMP put_smartRenameItemFactory(_In_ IPowerRenameItemFactory* pItemFactory);
IFACEMETHODIMP get_renameRegEx(_COM_Outptr_ IPowerRenameRegEx** ppRegEx);
IFACEMETHODIMP put_renameRegEx(_In_ IPowerRenameRegEx* pRegEx);
IFACEMETHODIMP get_renameItemFactory(_COM_Outptr_ IPowerRenameItemFactory** ppItemFactory);
IFACEMETHODIMP put_renameItemFactory(_In_ IPowerRenameItemFactory* pItemFactory);
// IPowerRenameRegExEvents
IFACEMETHODIMP OnSearchTermChanged(_In_ PCWSTR searchTerm);
@@ -99,7 +99,7 @@ protected:
DWORD m_cookie = 0;
DWORD m_regExAdviseCookie = 0;
struct SMART_RENAME_MGR_EVENT
struct RENAME_MGR_EVENT
{
IPowerRenameManagerEvents* pEvents;
DWORD cookie;
@@ -108,8 +108,8 @@ protected:
CComPtr<IPowerRenameItemFactory> m_spItemFactory;
CComPtr<IPowerRenameRegEx> m_spRegEx;
_Guarded_by_(m_lockEvents) std::vector<SMART_RENAME_MGR_EVENT> m_PowerRenameManagerEvents;
_Guarded_by_(m_lockItems) std::map<int, IPowerRenameItem*> m_smartRenameItems;
_Guarded_by_(m_lockEvents) std::vector<RENAME_MGR_EVENT> m_powerRenameManagerEvents;
_Guarded_by_(m_lockItems) std::map<int, IPowerRenameItem*> m_renameItems;
// Parent HWND used by IFileOperation
HWND m_hwndParent = nullptr;

View File

@@ -37,11 +37,11 @@ IFACEMETHODIMP CPowerRenameRegEx::Advise(_In_ IPowerRenameRegExEvents* regExEven
{
CSRWExclusiveAutoLock lock(&m_lockEvents);
m_cookie++;
SMART_RENAME_REGEX_EVENT srre;
RENAME_REGEX_EVENT srre;
srre.cookie = m_cookie;
srre.pEvents = regExEvents;
regExEvents->AddRef();
m_smartRenameRegExEvents.push_back(srre);
m_renameRegExEvents.push_back(srre);
*cookie = m_cookie;
@@ -53,16 +53,16 @@ IFACEMETHODIMP CPowerRenameRegEx::UnAdvise(_In_ DWORD cookie)
HRESULT hr = E_FAIL;
CSRWExclusiveAutoLock lock(&m_lockEvents);
for (auto it : m_smartRenameRegExEvents)
for (std::vector<RENAME_REGEX_EVENT>::iterator it = m_renameRegExEvents.begin(); it != m_renameRegExEvents.end(); ++it)
{
if (it.cookie == cookie)
if (it->cookie == cookie)
{
hr = S_OK;
it.cookie = 0;
if (it.pEvents)
it->cookie = 0;
if (it->pEvents)
{
it.pEvents->Release();
it.pEvents = nullptr;
it->pEvents->Release();
it->pEvents = nullptr;
}
break;
}
@@ -213,7 +213,7 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
std::wsmatch m;
if (std::regex_search(sourceToUse, m, pattern))
{
res = sourceToUse.replace(m.prefix().length(), searchTerm.length(), replaceTerm);
res = sourceToUse.replace(m.prefix().length(), m.length(), replaceTerm);
}
}
}
@@ -265,7 +265,7 @@ void CPowerRenameRegEx::_OnSearchTermChanged()
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_smartRenameRegExEvents)
for (auto it : m_renameRegExEvents)
{
if (it.pEvents)
{
@@ -278,7 +278,7 @@ void CPowerRenameRegEx::_OnReplaceTermChanged()
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_smartRenameRegExEvents)
for (auto it : m_renameRegExEvents)
{
if (it.pEvents)
{
@@ -291,7 +291,7 @@ void CPowerRenameRegEx::_OnFlagsChanged()
{
CSRWSharedAutoLock lock(&m_lockEvents);
for (auto it : m_smartRenameRegExEvents)
for (auto it : m_renameRegExEvents)
{
if (it.pEvents)
{

View File

@@ -46,13 +46,13 @@ protected:
DWORD m_cookie = 0;
struct SMART_RENAME_REGEX_EVENT
struct RENAME_REGEX_EVENT
{
IPowerRenameRegExEvents* pEvents;
DWORD cookie;
};
_Guarded_by_(m_lockEvents) std::vector<SMART_RENAME_REGEX_EVENT> m_smartRenameRegExEvents;
_Guarded_by_(m_lockEvents) std::vector<RENAME_REGEX_EVENT> m_renameRegExEvents;
long m_refCount = 0;
};

View File

@@ -0,0 +1,481 @@
#include "stdafx.h"
#include <commctrl.h>
#include "Settings.h"
const wchar_t c_rootRegPath[] = L"Software\\Microsoft\\PowerRename";
const wchar_t c_mruSearchRegPath[] = L"SearchMRU";
const wchar_t c_mruReplaceRegPath[] = L"ReplaceMRU";
const wchar_t c_enabled[] = L"Enabled";
const wchar_t c_showIconOnMenu[] = L"ShowIcon";
const wchar_t c_extendedContextMenuOnly[] = L"ExtendedContextMenuOnly";
const wchar_t c_persistState[] = L"PersistState";
const wchar_t c_maxMRUSize[] = L"MaxMRUSize";
const wchar_t c_flags[] = L"Flags";
const wchar_t c_searchText[] = L"SearchText";
const wchar_t c_replaceText[] = L"ReplaceText";
const wchar_t c_mruEnabled[] = L"MRUEnabled";
const bool c_enabledDefault = true;
const bool c_showIconOnMenuDefault = true;
const bool c_extendedContextMenuOnlyDefaut = false;
const bool c_persistStateDefault = true;
const bool c_mruEnabledDefault = true;
const DWORD c_maxMRUSizeDefault = 10;
const DWORD c_flagsDefault = 0;
bool CSettings::GetEnabled()
{
return GetRegBoolValue(c_enabled, c_enabledDefault);
}
bool CSettings::SetEnabled(_In_ bool enabled)
{
return SetRegBoolValue(c_enabled, enabled);
}
bool CSettings::GetShowIconOnMenu()
{
return GetRegBoolValue(c_showIconOnMenu, c_showIconOnMenuDefault);
}
bool CSettings::SetShowIconOnMenu(_In_ bool show)
{
return SetRegBoolValue(c_showIconOnMenu, show);
}
bool CSettings::GetExtendedContextMenuOnly()
{
return GetRegBoolValue(c_extendedContextMenuOnly, c_extendedContextMenuOnlyDefaut);
}
bool CSettings::SetExtendedContextMenuOnly(_In_ bool extendedOnly)
{
return SetRegBoolValue(c_extendedContextMenuOnly, extendedOnly);
}
bool CSettings::GetPersistState()
{
return GetRegBoolValue(c_persistState, c_persistStateDefault);
}
bool CSettings::SetPersistState(_In_ bool persistState)
{
return SetRegBoolValue(c_persistState, persistState);
}
bool CSettings::GetMRUEnabled()
{
return GetRegBoolValue(c_mruEnabled, c_mruEnabledDefault);
}
bool CSettings::SetMRUEnabled(_In_ bool enabled)
{
return SetRegBoolValue(c_mruEnabled, enabled);
}
DWORD CSettings::GetMaxMRUSize()
{
return GetRegDWORDValue(c_maxMRUSize, c_maxMRUSizeDefault);
}
bool CSettings::SetMaxMRUSize(_In_ DWORD maxMRUSize)
{
return SetRegDWORDValue(c_maxMRUSize, maxMRUSize);
}
DWORD CSettings::GetFlags()
{
return GetRegDWORDValue(c_flags, c_flagsDefault);
}
bool CSettings::SetFlags(_In_ DWORD flags)
{
return SetRegDWORDValue(c_flags, flags);
}
bool CSettings::GetSearchText(__out_ecount(cchBuf) PWSTR text, DWORD cchBuf)
{
return GetRegStringValue(c_searchText, text, cchBuf);
}
bool CSettings::SetSearchText(_In_ PCWSTR text)
{
return SetRegStringValue(c_searchText, text);
}
bool CSettings::GetReplaceText(__out_ecount(cchBuf) PWSTR text, DWORD cchBuf)
{
return GetRegStringValue(c_replaceText, text, cchBuf);
}
bool CSettings::SetReplaceText(_In_ PCWSTR text)
{
return SetRegStringValue(c_replaceText, text);
}
bool CSettings::SetRegBoolValue(_In_ PCWSTR valueName, _In_ bool value)
{
DWORD dwValue = value ? 1 : 0;
return SetRegDWORDValue(valueName, dwValue);
}
bool CSettings::GetRegBoolValue(_In_ PCWSTR valueName, _In_ bool defaultValue)
{
DWORD value = GetRegDWORDValue(valueName, (defaultValue == 0) ? false : true);
return (value == 0) ? false : true;
}
bool CSettings::SetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD value)
{
return (SUCCEEDED(HRESULT_FROM_WIN32(SHSetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, REG_DWORD, &value, sizeof(value)))));
}
DWORD CSettings::GetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD defaultValue)
{
DWORD retVal = defaultValue;
DWORD type = REG_DWORD;
DWORD dwEnabled = 0;
DWORD cb = sizeof(dwEnabled);
if (SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, &type, &dwEnabled, &cb) == ERROR_SUCCESS)
{
retVal = dwEnabled;
}
return retVal;
}
bool CSettings::SetRegStringValue(_In_ PCWSTR valueName, _In_ PCWSTR value)
{
ULONG cb = (DWORD)((wcslen(value) + 1) * sizeof(*value));
return (SUCCEEDED(HRESULT_FROM_WIN32(SHSetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, REG_SZ, (const BYTE*)value, cb))));
}
bool CSettings::GetRegStringValue(_In_ PCWSTR valueName, __out_ecount(cchBuf) PWSTR value, DWORD cchBuf)
{
if (cchBuf > 0)
{
value[0] = L'\0';
}
DWORD type = REG_SZ;
ULONG cb = cchBuf * sizeof(*value);
return (SUCCEEDED(HRESULT_FROM_WIN32(SHGetValue(HKEY_CURRENT_USER, c_rootRegPath, valueName, &type, value, &cb) == ERROR_SUCCESS)));
}
typedef int (CALLBACK* MRUCMPPROC)(LPCWSTR, LPCWSTR);
typedef struct {
DWORD cbSize;
UINT uMax;
UINT fFlags;
HKEY hKey;
LPCTSTR lpszSubKey;
MRUCMPPROC lpfnCompare;
} MRUINFO;
typedef HANDLE (*CreateMRUListFn)(MRUINFO* pmi);
typedef int (*AddMRUStringFn)(HANDLE hMRU, LPCWSTR data);
typedef int (*EnumMRUListFn)(HANDLE hMRU, int nItem, void* lpData, UINT uLen);
typedef int (*FreeMRUListFn)(HANDLE hMRU);
class CRenameMRU :
public IEnumString,
public IPowerRenameMRU
{
public:
// IUnknown
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv);
// IEnumString
IFACEMETHODIMP Next(__in ULONG celt, __out_ecount_part(celt, *pceltFetched) LPOLESTR* rgelt, __out_opt ULONG* pceltFetched);
IFACEMETHODIMP Skip(__in ULONG) { return E_NOTIMPL; }
IFACEMETHODIMP Reset();
IFACEMETHODIMP Clone(__deref_out IEnumString** ppenum) { *ppenum = nullptr; return E_NOTIMPL; }
// IPowerRenameMRU
IFACEMETHODIMP AddMRUString(_In_ PCWSTR entry);
static HRESULT CreateInstance(_In_ PCWSTR regPathMRU, _In_ ULONG maxMRUSize, _Outptr_ IUnknown** ppUnk);
private:
CRenameMRU();
~CRenameMRU();
HRESULT _Initialize(_In_ PCWSTR regPathMRU, __in ULONG maxMRUSize);
HRESULT _CreateMRUList(_In_ MRUINFO* pmi);
int _AddMRUString(_In_ PCWSTR data);
int _EnumMRUList(_In_ int nItem, _Out_ void* lpData, _In_ UINT uLen);
void _FreeMRUList();
long m_refCount = 0;
HKEY m_hKey = NULL;
ULONG m_maxMRUSize = 0;
ULONG m_mruIndex = 0;
ULONG m_mruSize = 0;
HANDLE m_mruHandle = NULL;
HMODULE m_hComctl32Dll = NULL;
PWSTR m_regPath = nullptr;
};
CRenameMRU::CRenameMRU() :
m_refCount(1)
{}
CRenameMRU::~CRenameMRU()
{
if (m_hKey)
{
RegCloseKey(m_hKey);
}
_FreeMRUList();
if (m_hComctl32Dll)
{
FreeLibrary(m_hComctl32Dll);
}
CoTaskMemFree(m_regPath);
}
HRESULT CRenameMRU::CreateInstance(_In_ PCWSTR regPathMRU, _In_ ULONG maxMRUSize, _Outptr_ IUnknown** ppUnk)
{
*ppUnk = nullptr;
HRESULT hr = (regPathMRU && maxMRUSize > 0) ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
CRenameMRU* renameMRU = new CRenameMRU();
hr = renameMRU ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = renameMRU->_Initialize(regPathMRU, maxMRUSize);
if (SUCCEEDED(hr))
{
hr = renameMRU->QueryInterface(IID_PPV_ARGS(ppUnk));
}
renameMRU->Release();
}
}
return hr;
}
// IUnknown
IFACEMETHODIMP_(ULONG) CRenameMRU::AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG) CRenameMRU::Release()
{
long refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
IFACEMETHODIMP CRenameMRU::QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv)
{
static const QITAB qit[] = {
QITABENT(CRenameMRU, IEnumString),
QITABENT(CRenameMRU, IPowerRenameMRU),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
HRESULT CRenameMRU::_Initialize(_In_ PCWSTR regPathMRU, __in ULONG maxMRUSize)
{
m_maxMRUSize = maxMRUSize;
wchar_t regPath[MAX_PATH] = { 0 };
HRESULT hr = StringCchPrintf(regPath, ARRAYSIZE(regPath), L"%s\\%s", c_rootRegPath, regPathMRU);
if (SUCCEEDED(hr))
{
hr = SHStrDup(regPathMRU, &m_regPath);
if (SUCCEEDED(hr))
{
MRUINFO mi = {
sizeof(MRUINFO),
maxMRUSize,
0,
HKEY_CURRENT_USER,
regPath,
nullptr
};
hr = _CreateMRUList(&mi);
if (SUCCEEDED(hr))
{
m_mruSize = _EnumMRUList(-1, NULL, 0);
}
else
{
hr = E_FAIL;
}
}
}
return hr;
}
// IEnumString
IFACEMETHODIMP CRenameMRU::Reset()
{
m_mruIndex = 0;
return S_OK;
}
#define MAX_ENTRY_STRING 1024
IFACEMETHODIMP CRenameMRU::Next(__in ULONG celt, __out_ecount_part(celt, *pceltFetched) LPOLESTR* rgelt, __out_opt ULONG* pceltFetched)
{
HRESULT hr = S_OK;
WCHAR mruEntry[MAX_ENTRY_STRING];
mruEntry[0] = L'\0';
if (pceltFetched)
{
*pceltFetched = 0;
}
if (!celt)
{
return S_OK;
}
if (!rgelt)
{
return S_FALSE;
}
hr = S_FALSE;
if (m_mruIndex <= m_mruSize && _EnumMRUList(m_mruIndex++, (void*)mruEntry, ARRAYSIZE(mruEntry)) > 0)
{
hr = SHStrDup(mruEntry, rgelt);
if (SUCCEEDED(hr) && pceltFetched != nullptr)
{
*pceltFetched = 1;
}
}
return hr;
}
IFACEMETHODIMP CRenameMRU::AddMRUString(_In_ PCWSTR entry)
{
return (_AddMRUString(entry) < 0) ? E_FAIL : S_OK;
}
HRESULT CRenameMRU::_CreateMRUList(_In_ MRUINFO* pmi)
{
if (m_mruHandle != NULL)
{
_FreeMRUList();
}
if (m_hComctl32Dll == NULL)
{
m_hComctl32Dll = LoadLibraryEx(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if (m_hComctl32Dll != nullptr)
{
CreateMRUListFn pfnCreateMRUList = reinterpret_cast<CreateMRUListFn>(GetProcAddress(m_hComctl32Dll, (LPCSTR)MAKEINTRESOURCE(400)));
if (pfnCreateMRUList != nullptr)
{
m_mruHandle = pfnCreateMRUList(pmi);
}
}
return (m_mruHandle != NULL) ? S_OK : E_FAIL;
}
int CRenameMRU::_AddMRUString(_In_ PCWSTR data)
{
int retVal = -1;
if (m_mruHandle != NULL)
{
if (m_hComctl32Dll == NULL)
{
m_hComctl32Dll = LoadLibraryEx(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if (m_hComctl32Dll != nullptr)
{
AddMRUStringFn pfnAddMRUString = reinterpret_cast<AddMRUStringFn>(GetProcAddress(m_hComctl32Dll, (LPCSTR)MAKEINTRESOURCE(401)));
if (pfnAddMRUString != nullptr)
{
retVal = pfnAddMRUString(m_mruHandle, data);
}
}
}
return retVal;
}
int CRenameMRU::_EnumMRUList(_In_ int nItem, _Out_ void* lpData, _In_ UINT uLen)
{
int retVal = -1;
if (m_mruHandle != NULL)
{
if (m_hComctl32Dll == NULL)
{
m_hComctl32Dll = LoadLibraryEx(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if (m_hComctl32Dll != nullptr)
{
EnumMRUListFn pfnEnumMRUList = reinterpret_cast<EnumMRUListFn>(GetProcAddress(m_hComctl32Dll, (LPCSTR)MAKEINTRESOURCE(403)));
if (pfnEnumMRUList != nullptr)
{
retVal = pfnEnumMRUList(m_mruHandle, nItem, lpData, uLen);
}
}
}
return retVal;
}
void CRenameMRU::_FreeMRUList()
{
if (m_mruHandle != NULL)
{
if (m_hComctl32Dll == NULL)
{
m_hComctl32Dll = LoadLibraryEx(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if (m_hComctl32Dll != nullptr)
{
FreeMRUListFn pfnFreeMRUList = reinterpret_cast<FreeMRUListFn>(GetProcAddress(m_hComctl32Dll, (LPCSTR)MAKEINTRESOURCE(152)));
if (pfnFreeMRUList != nullptr)
{
pfnFreeMRUList(m_mruHandle);
}
}
m_mruHandle = NULL;
}
}
HRESULT CRenameMRUSearch_CreateInstance(_Outptr_ IUnknown** ppUnk)
{
return CRenameMRU::CreateInstance(c_mruSearchRegPath, CSettings::GetMaxMRUSize(), ppUnk);
}
HRESULT CRenameMRUReplace_CreateInstance(_Outptr_ IUnknown** ppUnk)
{
return CRenameMRU::CreateInstance(c_mruReplaceRegPath, CSettings::GetMaxMRUSize(), ppUnk);
}

View File

@@ -0,0 +1,43 @@
#pragma once
class CSettings
{
public:
static bool GetEnabled();
static bool SetEnabled(_In_ bool enabled);
static bool GetShowIconOnMenu();
static bool SetShowIconOnMenu(_In_ bool show);
static bool GetExtendedContextMenuOnly();
static bool SetExtendedContextMenuOnly(_In_ bool extendedOnly);
static bool GetPersistState();
static bool SetPersistState(_In_ bool extendedOnly);
static bool GetMRUEnabled();
static bool SetMRUEnabled(_In_ bool enabled);
static DWORD GetMaxMRUSize();
static bool SetMaxMRUSize(_In_ DWORD maxMRUSize);
static DWORD GetFlags();
static bool SetFlags(_In_ DWORD flags);
static bool GetSearchText(__out_ecount(cchBuf) PWSTR text, DWORD cchBuf);
static bool SetSearchText(_In_ PCWSTR text);
static bool GetReplaceText(__out_ecount(cchBuf) PWSTR text, DWORD cchBuf);
static bool SetReplaceText(_In_ PCWSTR text);
private:
static bool GetRegBoolValue(_In_ PCWSTR valueName, _In_ bool defaultValue);
static bool SetRegBoolValue(_In_ PCWSTR valueName, _In_ bool value);
static bool SetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD value);
static DWORD GetRegDWORDValue(_In_ PCWSTR valueName, _In_ DWORD defaultValue);
static bool SetRegStringValue(_In_ PCWSTR valueName, _In_ PCWSTR value);
static bool GetRegStringValue(_In_ PCWSTR valueName, __out_ecount(cchBuf) PWSTR value, DWORD cchBuf);
};
HRESULT CRenameMRUSearch_CreateInstance(_Outptr_ IUnknown** ppUnk);
HRESULT CRenameMRUReplace_CreateInstance(_Outptr_ IUnknown** ppUnk);

View File

@@ -16,6 +16,7 @@
#include <pathcch.h>
#include <shobjidl.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <ProjectTelemetry.h>

View File

@@ -31,7 +31,7 @@ int APIENTRY wWinMain(
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
// Create the smart rename manager
// Create the rename manager
CComPtr<IPowerRenameManager> spsrm;
if (SUCCEEDED(CPowerRenameManager::s_CreateInstance(&spsrm)))
{
@@ -40,9 +40,9 @@ int APIENTRY wWinMain(
if (SUCCEEDED(CPowerRenameItem::s_CreateInstance(nullptr, IID_PPV_ARGS(&spsrif))))
{
// Pass the factory to the manager
if (SUCCEEDED(spsrm->put_smartRenameItemFactory(spsrif)))
if (SUCCEEDED(spsrm->put_renameItemFactory(spsrif)))
{
// Create the smart rename UI instance and pass the manager
// Create the rename UI instance and pass the manager
CComPtr<IPowerRenameUI> spsrui;
if (SUCCEEDED(CPowerRenameUI::s_CreateInstance(spsrm, nullptr, true, &spsrui)))
{

View File

@@ -1,190 +1,191 @@
<?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|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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>{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRenameTest</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</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|Win32'">
<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|Win32'">
<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)'=='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|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</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;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Resource.h" />
<ClInclude Include="PowerRenameTest.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="PowerRenameTest.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameTest.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<?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|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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>{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerRenameTest</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</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|Win32'">
<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|Win32'">
<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)'=='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|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\ui\;..\lib\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
</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;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..\;..\..\..\common;..\..\..\common\telemetry;..\..\</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)PowerRenameLib.lib;$(OutDir)PowerRenameUI.lib;Pathcch.lib;comctl32.lib;$(OutDir)..\..\src\modules\powerrename\UI\$(Platform)\$(Configuration)\PowerRenameUI.res;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>gdi32.dll;advapi32.dll;shell32.dll;ole32.dll;shlwapi.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Resource.h" />
<ClInclude Include="PowerRenameTest.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="PowerRenameTest.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameTest.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,6 +1,6 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by SmartRenameTest.rc
// Used by PowerRenameTest.rc
//
#define IDD_POWERRENAMETEST_DIALOG 402
#define IDR_MAINFRAME 428

View File

@@ -4,6 +4,7 @@
#include <commctrl.h>
#include <Shlobj.h>
#include <helpers.h>
#include <settings.h>
#include <windowsx.h>
extern HINSTANCE g_hInst;
@@ -32,16 +33,50 @@ struct FlagCheckboxMap
FlagCheckboxMap g_flagCheckboxMap[] =
{
{ UseRegularExpressions, IDC_CHECK_USEREGEX },
{ ExcludeSubfolders, IDC_CHECK_EXCLUDESUBFOLDERS },
{ EnumerateItems, IDC_CHECK_ENUMITEMS },
{ ExcludeFiles, IDC_CHECK_EXCLUDEFILES },
{ CaseSensitive, IDC_CHECK_CASESENSITIVE },
{ MatchAllOccurences, IDC_CHECK_MATCHALLOCCRENCES },
{ ExcludeFolders, IDC_CHECK_EXCLUDEFOLDERS },
{ NameOnly, IDC_CHECK_NAMEONLY },
{ ExtensionOnly, IDC_CHECK_EXTENSIONONLY }
{ ExcludeSubfolders, IDC_CHECK_EXCLUDESUBFOLDERS },
{ EnumerateItems, IDC_CHECK_ENUMITEMS },
{ ExcludeFiles, IDC_CHECK_EXCLUDEFILES },
{ CaseSensitive, IDC_CHECK_CASESENSITIVE },
{ MatchAllOccurences, IDC_CHECK_MATCHALLOCCURENCES },
{ ExcludeFolders, IDC_CHECK_EXCLUDEFOLDERS },
{ NameOnly, IDC_CHECK_NAMEONLY },
{ ExtensionOnly, IDC_CHECK_EXTENSIONONLY }
};
struct RepositionMap
{
DWORD id;
DWORD flags;
};
enum
{
Reposition_None = 0,
Reposition_X = 0x1,
Reposition_Y = 0x2,
Reposition_Width = 0x4,
Reposition_Height = 0x8
};
RepositionMap g_repositionMap[] =
{
{ IDC_SEARCHREPLACEGROUP, Reposition_Width },
{ IDC_OPTIONSGROUP, Reposition_Width },
{ IDC_PREVIEWGROUP, Reposition_Width | Reposition_Height },
{ IDC_EDIT_SEARCHFOR, Reposition_Width },
{ IDC_EDIT_REPLACEWITH, Reposition_Width },
{ IDC_LIST_PREVIEW, Reposition_Width | Reposition_Height },
{ IDC_STATUS_MESSAGE, Reposition_Y },
{ ID_RENAME, Reposition_X | Reposition_Y },
{ ID_ABOUT, Reposition_X | Reposition_Y },
{ IDCANCEL, Reposition_X | Reposition_Y }
};
inline int RECT_WIDTH(RECT& r) { return r.right - r.left; }
inline int RECT_HEIGHT(RECT& r) { return r.bottom - r.top; }
#define MAX_INPUT_STRING_LEN 1024
// IUnknown
IFACEMETHODIMP CPowerRenameUI::QueryInterface(__in REFIID riid, __deref_out void** ppv)
{
@@ -91,7 +126,7 @@ HRESULT CPowerRenameUI::s_CreateInstance(_In_ IPowerRenameManager* psrm, _In_opt
// IPowerRenameUI
IFACEMETHODIMP CPowerRenameUI::Show(_In_opt_ HWND hwndParent)
{
return _DoModal(hwndParent);
return _DoModeless(hwndParent);
}
IFACEMETHODIMP CPowerRenameUI::Close()
@@ -184,7 +219,7 @@ IFACEMETHODIMP CPowerRenameUI::OnRenameCompleted()
EnableWindow(m_hwnd, TRUE);
// Close the window
_OnCloseDlg();
PostMessage(m_hwnd, WM_CLOSE, (WPARAM)0, (LPARAM)0);
return S_OK;
}
@@ -229,8 +264,6 @@ IFACEMETHODIMP CPowerRenameUI::Drop(_In_ IDataObject* pdtobj, DWORD, POINTL pt,
m_spdth->Drop(pdtobj, &ptT, *pdwEffect);
}
_OnClear();
EnableWindow(GetDlgItem(m_hwnd, ID_RENAME), TRUE);
EnableWindow(m_hwndLV, TRUE);
@@ -245,7 +278,7 @@ IFACEMETHODIMP CPowerRenameUI::Drop(_In_ IDataObject* pdtobj, DWORD, POINTL pt,
HRESULT CPowerRenameUI::_Initialize(_In_ IPowerRenameManager* psrm, _In_opt_ IDataObject* pdo, _In_ bool enableDragDrop)
{
// Cache the smart rename manager
// Cache the rename manager
m_spsrm = psrm;
// Cache the data object for enumeration later
@@ -256,7 +289,7 @@ HRESULT CPowerRenameUI::_Initialize(_In_ IPowerRenameManager* psrm, _In_opt_ IDa
HRESULT hr = CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&m_spdth));
if (SUCCEEDED(hr))
{
// Subscribe to smart rename manager events
// Subscribe to rename manager events
hr = m_spsrm->Advise(this, &m_cookie);
}
@@ -268,6 +301,46 @@ HRESULT CPowerRenameUI::_Initialize(_In_ IPowerRenameManager* psrm, _In_opt_ IDa
return hr;
}
HRESULT CPowerRenameUI::_InitAutoComplete()
{
HRESULT hr = S_OK;
if (CSettings::GetMRUEnabled())
{
hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&m_spSearchAC));
if (SUCCEEDED(hr))
{
hr = CRenameMRUSearch_CreateInstance(&m_spSearchACL);
if (SUCCEEDED(hr))
{
hr = m_spSearchAC->Init(GetDlgItem(m_hwnd, IDC_EDIT_SEARCHFOR), m_spSearchACL, nullptr, nullptr);
if (SUCCEEDED(hr))
{
hr = m_spSearchAC->SetOptions(ACO_AUTOSUGGEST | ACO_AUTOAPPEND | ACO_UPDOWNKEYDROPSLIST);
}
}
}
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&m_spReplaceAC));
if (SUCCEEDED(hr))
{
hr = CRenameMRUReplace_CreateInstance(&m_spReplaceACL);
if (SUCCEEDED(hr))
{
hr = m_spReplaceAC->Init(GetDlgItem(m_hwnd, IDC_EDIT_REPLACEWITH), m_spReplaceACL, nullptr, nullptr);
if (SUCCEEDED(hr))
{
hr = m_spReplaceAC->SetOptions(ACO_AUTOSUGGEST | ACO_AUTOAPPEND | ACO_UPDOWNKEYDROPSLIST);
}
}
}
}
}
return hr;
}
void CPowerRenameUI::_Cleanup()
{
if (m_spsrm && m_cookie != 0)
@@ -284,6 +357,8 @@ void CPowerRenameUI::_Cleanup()
{
RevokeDragDrop(m_hwnd);
}
m_hwnd = NULL;
}
void CPowerRenameUI::_EnumerateItems(_In_ IDataObject* pdtobj)
@@ -303,31 +378,98 @@ void CPowerRenameUI::_EnumerateItems(_In_ IDataObject* pdtobj)
}
}
// TODO: persist settings made in the UI
HRESULT CPowerRenameUI::_ReadSettings()
{
// Check if we should read flags from settings
// or the defaults from the manager.
DWORD flags = 0;
if (CSettings::GetPersistState())
{
flags = CSettings::GetFlags();
m_spsrm->put_flags(flags);
wchar_t buffer[MAX_INPUT_STRING_LEN];
buffer[0] = L'\0';
CSettings::GetSearchText(buffer, ARRAYSIZE(buffer));
SetDlgItemText(m_hwnd, IDC_EDIT_SEARCHFOR, buffer);
buffer[0] = L'\0';
CSettings::GetReplaceText(buffer, ARRAYSIZE(buffer));
SetDlgItemText(m_hwnd, IDC_EDIT_REPLACEWITH, buffer);
}
else
{
m_spsrm->get_flags(&flags);
}
_SetCheckboxesFromFlags(flags);
return S_OK;
}
HRESULT CPowerRenameUI::_WriteSettings()
{
return S_OK;
}
// Check if we should store our settings
if (CSettings::GetPersistState())
{
DWORD flags = 0;
m_spsrm->get_flags(&flags);
CSettings::SetFlags(flags);
void CPowerRenameUI::_OnClear()
{
wchar_t buffer[MAX_INPUT_STRING_LEN];
buffer[0] = L'\0';
GetDlgItemText(m_hwnd, IDC_EDIT_SEARCHFOR, buffer, ARRAYSIZE(buffer));
CSettings::SetSearchText(buffer);
if (CSettings::GetMRUEnabled() && m_spSearchACL)
{
CComPtr<IPowerRenameMRU> spSearchMRU;
if (SUCCEEDED(m_spSearchACL->QueryInterface(IID_PPV_ARGS(&spSearchMRU))))
{
spSearchMRU->AddMRUString(buffer);
}
}
buffer[0] = L'\0';
GetDlgItemText(m_hwnd, IDC_EDIT_REPLACEWITH, buffer, ARRAYSIZE(buffer));
CSettings::SetReplaceText(buffer);
if (CSettings::GetMRUEnabled() && m_spReplaceACL)
{
CComPtr<IPowerRenameMRU> spReplaceMRU;
if (SUCCEEDED(m_spReplaceACL->QueryInterface(IID_PPV_ARGS(&spReplaceMRU))))
{
spReplaceMRU->AddMRUString(buffer);
}
}
}
return S_OK;
}
void CPowerRenameUI::_OnCloseDlg()
{
// Persist the current settings
_WriteSettings();
EndDialog(m_hwnd, 1);
if (m_hwnd != NULL)
{
if (m_modeless)
{
DestroyWindow(m_hwnd);
}
else
{
EndDialog(m_hwnd, 1);
}
}
}
void CPowerRenameUI::_OnDestroyDlg()
{
_Cleanup();
if (m_modeless)
{
PostQuitMessage(0);
}
}
void CPowerRenameUI::_OnRename()
@@ -336,6 +478,11 @@ void CPowerRenameUI::_OnRename()
{
m_spsrm->Rename(m_hwnd);
}
// Persist the current settings. We only do this when
// a rename is actually performed. Not when the user
// closes/cancels the dialog.
_WriteSettings();
}
void CPowerRenameUI::_OnAbout()
@@ -352,6 +499,7 @@ void CPowerRenameUI::_OnAbout()
HRESULT CPowerRenameUI::_DoModal(__in_opt HWND hwnd)
{
m_modeless = false;
HRESULT hr = S_OK;
INT_PTR ret = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_MAIN), hwnd, s_DlgProc, (LPARAM)this);
if (ret < 0)
@@ -361,6 +509,33 @@ HRESULT CPowerRenameUI::_DoModal(__in_opt HWND hwnd)
return hr;
}
HRESULT CPowerRenameUI::_DoModeless(__in_opt HWND hwnd)
{
m_modeless = true;
HRESULT hr = S_OK;
if (NULL != CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MAIN), hwnd, s_DlgProc, (LPARAM)this))
{
ShowWindow(m_hwnd, SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(m_hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
DestroyWindow(m_hwnd);
m_hwnd = NULL;
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
INT_PTR CPowerRenameUI::_DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR bRet = TRUE; // default for all handled cases in switch below
@@ -379,6 +554,18 @@ INT_PTR CPowerRenameUI::_DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
bRet = _OnNotify(wParam, lParam);
break;
case WM_THEMECHANGED:
_OnSize(SIZE_RESTORED);
break;
case WM_SIZE:
_OnSize(wParam);
break;
case WM_GETMINMAXINFO:
_OnGetMinMaxInfo(lParam);
break;
case WM_CLOSE:
_OnCloseDlg();
break;
@@ -405,8 +592,26 @@ void CPowerRenameUI::_OnInitDlg()
// Initialize checkboxes from flags
if (m_spsrm)
{
// Check if we should read flags from settings
// or the defaults from the manager.
DWORD flags = 0;
m_spsrm->get_flags(&flags);
if (CSettings::GetPersistState())
{
flags = CSettings::GetFlags();
wchar_t buffer[MAX_INPUT_STRING_LEN];
buffer[0] = L'\0';
CSettings::GetSearchText(buffer, ARRAYSIZE(buffer));
SetDlgItemText(m_hwnd, IDC_EDIT_SEARCHFOR, buffer);
buffer[0] = L'\0';
CSettings::GetReplaceText(buffer, ARRAYSIZE(buffer));
SetDlgItemText(m_hwnd, IDC_EDIT_REPLACEWITH, buffer);
}
else
{
m_spsrm->get_flags(&flags);
}
_SetCheckboxesFromFlags(flags);
}
@@ -429,6 +634,15 @@ void CPowerRenameUI::_OnInitDlg()
RegisterDragDrop(m_hwnd, this);
}
RECT rc = { 0 };
GetWindowRect(m_hwnd, &rc);
m_initialWidth = RECT_WIDTH(rc);
m_initialHeight = RECT_HEIGHT(rc);
m_lastWidth = m_initialWidth;
m_lastHeight = m_initialHeight;
_InitAutoComplete();
// Disable rename button by default. It will be enabled in _UpdateCounts if
// there are tiems to be renamed
EnableWindow(GetDlgItem(m_hwnd, ID_RENAME), FALSE);
@@ -469,7 +683,7 @@ void CPowerRenameUI::_OnCommand(_In_ WPARAM wParam, _In_ LPARAM lParam)
case IDC_CHECK_EXCLUDEFILES:
case IDC_CHECK_EXCLUDEFOLDERS:
case IDC_CHECK_EXCLUDESUBFOLDERS:
case IDC_CHECK_MATCHALLOCCRENCES:
case IDC_CHECK_MATCHALLOCCURENCES:
case IDC_CHECK_USEREGEX:
case IDC_CHECK_EXTENSIONONLY:
case IDC_CHECK_NAMEONLY:
@@ -543,13 +757,98 @@ BOOL CPowerRenameUI::_OnNotify(_In_ WPARAM wParam, _In_ LPARAM lParam)
return ret;
}
void CPowerRenameUI::_OnGetMinMaxInfo(_In_ LPARAM lParam)
{
if (m_initialWidth)
{
// Prevent resizing the dialog less than the original size
MINMAXINFO* pMinMaxInfo = reinterpret_cast<MINMAXINFO*>(lParam);
pMinMaxInfo->ptMinTrackSize.x = m_initialWidth;
pMinMaxInfo->ptMinTrackSize.y = m_initialHeight;
}
}
void CPowerRenameUI::_OnSize(_In_ WPARAM wParam)
{
if ((wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) && m_initialWidth)
{
// Calculate window size change delta
RECT rc = { 0 };
GetWindowRect(m_hwnd, &rc);
const int xDelta = RECT_WIDTH(rc) - m_lastWidth;
m_lastWidth += xDelta;
const int yDelta = RECT_HEIGHT(rc) - m_lastHeight;
m_lastHeight += yDelta;
for (UINT u = 0; u < ARRAYSIZE(g_repositionMap); u++)
{
_MoveControl(g_repositionMap[u].id, g_repositionMap[u].flags, xDelta, yDelta);
}
m_listview.OnSize();
}
}
void CPowerRenameUI::_MoveControl(_In_ DWORD id, _In_ DWORD repositionFlags, _In_ int xDelta, _In_ int yDelta)
{
HWND hwnd = GetDlgItem(m_hwnd, id);
UINT flags = SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE;
if (!((repositionFlags & Reposition_X) || (repositionFlags & Reposition_Y)))
{
flags |= SWP_NOMOVE;
}
if (!((repositionFlags & Reposition_Width) || (repositionFlags & Reposition_Height)))
{
flags |= SWP_NOSIZE;
}
RECT rcWindow = { 0 };
GetWindowRect(hwnd, &rcWindow);
int cx = RECT_WIDTH(rcWindow);
int cy = RECT_HEIGHT(rcWindow);
MapWindowPoints(HWND_DESKTOP, GetParent(hwnd), (LPPOINT)&rcWindow, 2);
int x = rcWindow.left;
int y = rcWindow.top;
if (repositionFlags & Reposition_X)
{
x += xDelta;
}
if (repositionFlags & Reposition_Y)
{
y += yDelta;
}
if (repositionFlags & Reposition_Width)
{
cx += xDelta;
}
if (repositionFlags & Reposition_Height)
{
cy += yDelta;
}
SetWindowPos(hwnd, NULL, x, y, cx, cy, flags);
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
}
void CPowerRenameUI::_OnSearchReplaceChanged()
{
// Pass updated search and replace terms to the IPowerRenameRegEx handler
CComPtr<IPowerRenameRegEx> spRegEx;
if (m_spsrm && SUCCEEDED(m_spsrm->get_smartRenameRegEx(&spRegEx)))
if (m_spsrm && SUCCEEDED(m_spsrm->get_renameRegEx(&spRegEx)))
{
wchar_t buffer[MAX_PATH] = { 0 };
wchar_t buffer[MAX_INPUT_STRING_LEN];
buffer[0] = L'\0';
GetDlgItemText(m_hwnd, IDC_EDIT_SEARCHFOR, buffer, ARRAYSIZE(buffer));
spRegEx->put_searchTerm(buffer);
@@ -655,7 +954,7 @@ void CPowerRenameListView::Init(_In_ HWND hwndLV)
SetWindowLongPtr(m_hwndLV, GWL_STYLE, dwLVStyle);
// Set the extended view styles
ListView_SetExtendedListViewStyle(m_hwndLV, LVS_EX_CHECKBOXES | LVS_EX_DOUBLEBUFFER);
ListView_SetExtendedListViewStyle(m_hwndLV, LVS_EX_CHECKBOXES | LVS_EX_DOUBLEBUFFER | LVS_EX_AUTOSIZECOLUMNS);
// Get the system image lists. Our list view is setup to not destroy
// these since the image list belongs to the entire explorer process
@@ -837,6 +1136,14 @@ void CPowerRenameListView::GetDisplayInfo(_In_ IPowerRenameManager* psrm, _Inout
}
}
void CPowerRenameListView::OnSize()
{
RECT rc = { 0 };
GetClientRect(m_hwndLV, &rc);
ListView_SetColumnWidth(m_hwndLV, 0, RECT_WIDTH(rc) / 2);
ListView_SetColumnWidth(m_hwndLV, 1, RECT_WIDTH(rc) / 2);
}
void CPowerRenameListView::RedrawItems(_In_ int first, _In_ int last)
{
ListView_RedrawItems(m_hwndLV, first, last);
@@ -908,14 +1215,15 @@ void CPowerRenameListView::_UpdateHeaderCheckState(_In_ bool check)
HWND hwndHeader = ListView_GetHeader(m_hwndLV);
if (hwndHeader)
{
wchar_t szBuff[MAX_PATH] = { 0 };
wchar_t buffer[MAX_PATH] = { 0 };
buffer[0] = L'\0';
// Retrieve the existing header first so we
// don't trash the text already there
HDITEM hdi = { 0 };
hdi.mask = HDI_FORMAT | HDI_TEXT;
hdi.pszText = szBuff;
hdi.cchTextMax = ARRAYSIZE(szBuff);
hdi.pszText = buffer;
hdi.cchTextMax = ARRAYSIZE(buffer);
Header_GetItem(hwndHeader, 0, &hdi);

View File

@@ -1,9 +1,9 @@
#pragma once
#include <PowerRenameInterfaces.h>
#include <shldisp.h>
class CPowerRenameListView
{
public:
CPowerRenameListView() = default;
~CPowerRenameListView() = default;
@@ -17,6 +17,7 @@ public:
void OnKeyDown(_In_ IPowerRenameManager* psrm, _In_ LV_KEYDOWN* lvKeyDown);
void OnClickList(_In_ IPowerRenameManager* psrm, NM_LISTVIEW* pnmListView);
void GetDisplayInfo(_In_ IPowerRenameManager* psrm, _Inout_ LV_DISPINFO* plvdi);
void OnSize();
HWND GetHWND() { return m_hwndLV; }
private:
@@ -77,6 +78,7 @@ private:
}
HRESULT _DoModal(__in_opt HWND hwnd);
HRESULT _DoModeless(__in_opt HWND hwnd);
static INT_PTR CALLBACK s_DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
@@ -90,20 +92,22 @@ private:
return pDlg ? pDlg->_DlgProc(uMsg, wParam, lParam) : FALSE;
}
HRESULT _Initialize(_In_ IPowerRenameManager* psrm, _In_opt_ IDataObject* pdo, _In_ bool enableDragDrop);
HRESULT _InitAutoComplete();
void _Cleanup();
INT_PTR _DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
void _OnCommand(_In_ WPARAM wParam, _In_ LPARAM lParam);
BOOL _OnNotify(_In_ WPARAM wParam, _In_ LPARAM lParam);
HRESULT _Initialize(_In_ IPowerRenameManager* psrm, _In_opt_ IDataObject* pdo, _In_ bool enableDragDrop);
void _Cleanup();
void _OnSize(_In_ WPARAM wParam);
void _OnGetMinMaxInfo(_In_ LPARAM lParam);
void _OnInitDlg();
void _OnRename();
void _OnAbout();
void _OnCloseDlg();
void _OnDestroyDlg();
void _OnClear();
void _OnSearchReplaceChanged();
void _MoveControl(_In_ DWORD id, _In_ DWORD repositionFlags, _In_ int xDelta, _In_ int yDelta);
HRESULT _ReadSettings();
HRESULT _WriteSettings();
@@ -119,6 +123,7 @@ private:
bool m_initialized = false;
bool m_enableDragDrop = false;
bool m_disableCountUpdate = false;
bool m_modeless = true;
HWND m_hwnd = nullptr;
HWND m_hwndLV = nullptr;
HICON m_iconMain = nullptr;
@@ -126,8 +131,16 @@ private:
DWORD m_currentRegExId = 0;
UINT m_selectedCount = 0;
UINT m_renamingCount = 0;
int m_initialWidth = 0;
int m_initialHeight = 0;
int m_lastWidth = 0;
int m_lastHeight = 0;
CComPtr<IPowerRenameManager> m_spsrm;
CComPtr<IDataObject> m_spdo;
CComPtr<IDropTargetHelper> m_spdth;
CComPtr<IAutoComplete2> m_spSearchAC;
CComPtr<IUnknown> m_spSearchACL;
CComPtr<IAutoComplete2> m_spReplaceAC;
CComPtr<IUnknown> m_spReplaceACL;
CPowerRenameListView m_listview;
};

View File

@@ -79,7 +79,7 @@ namespace PowerRenameManagerTests
// TODO: Setup match and replace parameters
CComPtr<IPowerRenameRegEx> renRegEx;
Assert::IsTrue(mgr->get_smartRenameRegEx(&renRegEx) == S_OK);
Assert::IsTrue(mgr->get_renameRegEx(&renRegEx) == S_OK);
renRegEx->put_flags(flags);
renRegEx->put_searchTerm(searchTerm.c_str());
renRegEx->put_replaceTerm(replaceTerm.c_str());
@@ -125,7 +125,7 @@ namespace PowerRenameManagerTests
Assert::IsTrue(mgr->Shutdown() == S_OK);
}
TEST_METHOD(VerifySmartManagerEvents)
TEST_METHOD(VerifyRenameManagerEvents)
{
CComPtr<IPowerRenameManager> mgr;
Assert::IsTrue(CPowerRenameManager::s_CreateInstance(&mgr) == S_OK);

View File

@@ -101,6 +101,7 @@ void OverlayWindow::enable() {
void OverlayWindow::disable(bool trace_event) {
if (_enabled) {
_enabled = false;
if (trace_event) {
Trace::EnableShortcutGuide(false);
}
@@ -111,7 +112,6 @@ void OverlayWindow::disable(bool trace_event) {
target_state = nullptr;
winkey_popup = nullptr;
}
_enabled = false;
}
void OverlayWindow::disable() {

View File

@@ -21,6 +21,9 @@ public:
virtual bool is_enabled() override;
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override;
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override { }
virtual void signal_system_menu_action(const wchar_t* name) override { }
void on_held();
void on_held_press(DWORD vkCode);
void quick_hide();

View File

@@ -35,6 +35,7 @@ web::json::value get_general_settings() {
result.as_object()[L"theme"] = json::value::string(settings_theme);
result.as_object()[L"system_theme"] = json::value::string(WindowsColors::is_dark_mode() ? L"dark" : L"light");
result.as_object()[L"powertoys_version"] = json::value::string(get_product_version());
return result;
}

View File

@@ -18,7 +18,16 @@ namespace {
}
}
// Prevent system-wide input lagging while paused in the debugger
//#define DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED
void start_lowlevel_keyboard_hook() {
#if defined(_DEBUG) && defined(DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED)
if(IsDebuggerPresent()) {
return;
}
#endif
if (!hook_handle) {
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, hook_proc, GetModuleHandle(NULL), NULL);
hook_handle_copy = hook_handle;

View File

@@ -8,6 +8,8 @@
#include "trace.h"
#include "general_settings.h"
#include <common/dpi_aware.h>
#if _DEBUG && _WIN64
#include "unhandled_exception_handler.h"
#endif
@@ -31,6 +33,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
// The app is already running
return 0;
}
DPIAware::EnableDPIAwarenessForThisProcess();
#if _DEBUG && _WIN64
//Global error handlers to diagnose errors.

View File

@@ -20,5 +20,6 @@ PowertoyModule load_powertoy(const std::wstring& filename) {
FreeLibrary(handle);
winrt::throw_last_error();
}
module->register_system_menu_helper(&SystemMenuHelperInstace());
return PowertoyModule(module, handle);
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include "powertoys_events.h"
#include "system_menu_helper.h"
#include <interface/powertoy_module_interface.h>
#include <string>
#include <memory>
@@ -12,6 +13,7 @@ class PowertoyModule;
struct PowertoyModuleDeleter {
void operator()(PowertoyModuleIface* module) const {
if (module) {
powertoys_events().unregister_system_menu_action(module);
powertoys_events().unregister_receiver(module);
module->destroy();
}
@@ -38,6 +40,9 @@ public:
powertoys_events().register_receiver(*want_signals, module);
}
}
if (SystemMenuHelperInstace().HasCustomConfig(module)) {
powertoys_events().register_system_menu_action(module);
}
}
const std::wstring& get_name() const {

View File

@@ -2,6 +2,7 @@
#include "powertoys_events.h"
#include "lowlevel_keyboard_event.h"
#include "win_hook_event.h"
#include "system_menu_helper.h"
void first_subscribed(const std::wstring& event) {
if (event == ll_keyboard)
@@ -41,6 +42,37 @@ void PowertoysEvents::unregister_receiver(PowertoyModuleIface* module) {
}
}
void PowertoysEvents::register_system_menu_action(PowertoyModuleIface* module) {
std::unique_lock lock(mutex);
system_menu_receivers.insert(module);
}
void PowertoysEvents::unregister_system_menu_action(PowertoyModuleIface* module) {
std::unique_lock lock(mutex);
auto it = system_menu_receivers.find(module);
if (it != system_menu_receivers.end()) {
SystemMenuHelperInstace().Reset(module);
system_menu_receivers.erase(it);
}
}
void PowertoysEvents::handle_system_menu_action(const WinHookEvent& data) {
if (data.event == EVENT_SYSTEM_MENUSTART) {
for (auto& module : system_menu_receivers) {
SystemMenuHelperInstace().Customize(module, data.hwnd);
}
}
else if (data.event == EVENT_OBJECT_INVOKED) {
if (PowertoyModuleIface* module{ SystemMenuHelperInstace().ModuleFromItemId(data.idChild) }) {
std::wstring itemName = SystemMenuHelperInstace().ItemNameFromItemId(data.idChild);
// Process event on specified system menu item by responsible module.
module->signal_system_menu_action(itemName.c_str());
// Process event on specified system menu item by system menu helper (check/uncheck if needed).
SystemMenuHelperInstace().ProcessSelectedItem(module, GetForegroundWindow(), itemName.c_str());
}
}
}
intptr_t PowertoysEvents::signal_event(const std::wstring & event, intptr_t data) {
intptr_t rvalue = 0;
std::shared_lock lock(mutex);

View File

@@ -1,15 +1,23 @@
#pragma once
#include <interface/powertoy_module_interface.h>
#include <interface/win_hook_event_data.h>
#include <string>
class PowertoysEvents {
public:
void register_receiver(const std::wstring& event, PowertoyModuleIface* module);
void unregister_receiver(PowertoyModuleIface* module);
void register_system_menu_action(PowertoyModuleIface* module);
void unregister_system_menu_action(PowertoyModuleIface* module);
void handle_system_menu_action(const WinHookEvent& data);
intptr_t signal_event(const std::wstring& event, intptr_t data);
private:
std::shared_mutex mutex;
std::unordered_map<std::wstring, std::vector<PowertoyModuleIface*>> receivers;
std::unordered_set<PowertoyModuleIface*> system_menu_receivers;
};
PowertoysEvents& powertoys_events();

View File

@@ -67,7 +67,7 @@
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<EnableDpiAwareness>false</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -92,7 +92,7 @@
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<EnableDpiAwareness>false</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
@@ -107,6 +107,7 @@
<ClCompile Include="powertoy_module.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="settings_window.cpp" />
<ClCompile Include="system_menu_helper.cpp" />
<ClCompile Include="trace.cpp" />
<ClCompile Include="tray_icon.cpp" />
<ClCompile Include="unhandled_exception_handler.cpp" />
@@ -121,6 +122,7 @@
<ClInclude Include="powertoy_module.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="settings_window.h" />
<ClInclude Include="system_menu_helper.h" />
<ClInclude Include="trace.h" />
<ClInclude Include="tray_icon.h" />
<ClInclude Include="unhandled_exception_handler.h" />

View File

@@ -33,6 +33,9 @@
<ClCompile Include="win_hook_event.cpp">
<Filter>Events</Filter>
</ClCompile>
<ClCompile Include="system_menu_helper.cpp">
<Filter>Utils</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@@ -67,6 +70,9 @@
<ClInclude Include="win_hook_event.h">
<Filter>Events</Filter>
</ClInclude>
<ClInclude Include="system_menu_helper.h">
<Filter>Utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Utils">

View File

@@ -0,0 +1,129 @@
#include "pch.h"
#include "system_menu_helper.h"
#include <interface/powertoy_module_interface.h>
namespace {
constexpr int KSeparatorPos = 1;
constexpr int KNewItemPos = 2;
unsigned int GenerateItemId() {
static unsigned int generator = 0x70777479;
return ++generator;
}
}
SystemMenuHelper& SystemMenuHelperInstace() {
static SystemMenuHelper instance;
return instance;
}
void SystemMenuHelper::SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) {
Reset(module);
Configurations[module] = config;
for (auto& [window, modules] : ProcessedModules) {
// Unregister module. After system menu is opened again, new configuration will be applied.
modules.erase(std::remove(std::begin(modules), std::end(modules), module), std::end(modules));
}
}
void SystemMenuHelper::ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) {
for (const auto& item : Configurations[module]) {
if (itemName == item.name && item.checkBox) {
// Handle check/uncheck action only if specified by module configuration.
for (const auto& [id, data] : IdMappings) {
if (data.second == itemName) {
HMENU systemMenu = GetSystemMenu(window, false);
int state = (GetMenuState(systemMenu, id, MF_BYCOMMAND) == MF_CHECKED) ? MF_UNCHECKED : MF_CHECKED;
CheckMenuItem(systemMenu, id, MF_BYCOMMAND | state);
break;
}
}
break;
}
}
}
bool SystemMenuHelper::Customize(PowertoyModuleIface* module, HWND window) {
auto& modules = ProcessedModules[window];
for (const auto& m : modules) {
if (module == m) {
return false;
}
}
AddSeparator(module, window);
for (const auto& info : Configurations[module]) {
AddItem(module, window, info.name, info.enable);
}
modules.push_back(module);
return true;
}
void SystemMenuHelper::Reset(PowertoyModuleIface* module) {
for (auto& [window, modules] : ProcessedModules) {
if (HMENU systemMenu{ GetSystemMenu(window, false) }) {
for (auto& [id, data] : IdMappings) {
if (data.first == module) {
DeleteMenu(systemMenu, id, MF_BYCOMMAND);
}
}
}
}
}
bool SystemMenuHelper::HasCustomConfig(PowertoyModuleIface* module) {
return Configurations.find(module) != Configurations.end();
}
bool SystemMenuHelper::AddItem(PowertoyModuleIface* module, HWND window, const std::wstring& name, const bool enable) {
if (HMENU systemMenu{ GetSystemMenu(window, false) }) {
MENUITEMINFO item;
item.cbSize = sizeof(item);
item.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
item.fState = MF_UNCHECKED | MF_DISABLED; // Item is disabled by default.
item.wID = GenerateItemId();
item.dwTypeData = const_cast<WCHAR*>(name.c_str());
item.cch = name.size() + 1;
if (InsertMenuItem(systemMenu, GetMenuItemCount(systemMenu) - KNewItemPos, true, &item)) {
IdMappings[item.wID] = { module, name };
if (enable) {
EnableMenuItem(systemMenu, item.wID, MF_BYCOMMAND | MF_ENABLED);
}
return true;
}
}
return false;
}
bool SystemMenuHelper::AddSeparator(PowertoyModuleIface* module, HWND window) {
if (HMENU systemMenu{ GetSystemMenu(window, false) }) {
MENUITEMINFO separator;
separator.cbSize = sizeof(separator);
separator.fMask = MIIM_ID | MIIM_FTYPE;
separator.fType = MFT_SEPARATOR;
separator.wID = GenerateItemId();
if (InsertMenuItem(systemMenu, GetMenuItemCount(systemMenu) - KSeparatorPos, true, &separator)) {
IdMappings[separator.wID] = { module, L"sepparator_dummy_name" };
return true;
}
}
return false;
}
PowertoyModuleIface* SystemMenuHelper::ModuleFromItemId(const int& id) {
auto it = IdMappings.find(id);
if (it != IdMappings.end()) {
return it->second.first;
}
return nullptr;
}
const std::wstring SystemMenuHelper::ItemNameFromItemId(const int& id) {
auto itemIt = IdMappings.find(id);
if (itemIt != IdMappings.end()) {
return itemIt->second.second;
}
return std::wstring{};
}

View File

@@ -0,0 +1,42 @@
#pragma once
#pragma once
#include <interface/powertoy_system_menu.h>
#include <windows.h>
#include <string>
#include <vector>
#include <unordered_map>
class PowertoyModuleIface;
class SystemMenuHelper : public PowertoySystemMenuIface {
public:
// PowertoySystemMenuIface
virtual void SetConfiguration(PowertoyModuleIface* module, const std::vector<ItemInfo>& config) override;
virtual void ProcessSelectedItem(PowertoyModuleIface* module, HWND window, const wchar_t* itemName) override;
bool Customize(PowertoyModuleIface* module, HWND window);
void Reset(PowertoyModuleIface* module);
bool HasCustomConfig(PowertoyModuleIface* module);
PowertoyModuleIface* ModuleFromItemId(const int& id);
const std::wstring ItemNameFromItemId(const int& id);
private:
bool AddItem(PowertoyModuleIface* module, HWND window, const std::wstring& name, const bool enable);
bool AddSeparator(PowertoyModuleIface* module, HWND window);
// Store processed modules per window to avoid handling it multiple times.
std::unordered_map<HWND, std::vector<PowertoyModuleIface*>> ProcessedModules{};
// Keep mappings form item id to the module who created it and item name for faster processing later.
std::unordered_map<int, std::pair<PowertoyModuleIface*, std::wstring>> IdMappings{};
// Store configurations provided by module.
// This will be used to create custom system menu items and to handle updates.
std::unordered_map<PowertoyModuleIface*, std::vector<ItemInfo>> Configurations{};
};
SystemMenuHelper& SystemMenuHelperInstace();

View File

@@ -6,20 +6,24 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
HWND tray_icon_hwnd = NULL;
namespace {
HWND tray_icon_hwnd = NULL;
// Message code that Windows will use for tray icon notifications.
UINT wm_icon_notify = 0;
// Message code that Windows will use for tray icon notifications.
UINT wm_icon_notify = 0;
// Contains the Windows Message for taskbar creation.
UINT wm_taskbar_restart = 0;
UINT wm_run_on_main_ui_thread = 0;
// Contains the Windows Message for taskbar creation.
UINT wm_taskbar_restart = 0;
UINT wm_run_on_main_ui_thread = 0;
NOTIFYICONDATAW tray_icon_data;
static bool about_box_shown = false;
NOTIFYICONDATAW tray_icon_data;
bool tray_icon_created = false;
HMENU h_menu = nullptr;
HMENU h_sub_menu = nullptr;
bool about_box_shown = false;
HMENU h_menu = nullptr;
HMENU h_sub_menu = nullptr;
}
// Struct to fill with callback and the data. The window_proc is responsible for cleaning it.
struct run_on_main_ui_thread_msg {
@@ -77,6 +81,16 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
break;
}
break;
// Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it.
// We'll also never receive wm_taskbar_restart message if the first call to Shell_NotifyIcon failed, so we use
// WM_WINDOWPOSCHANGING which is always received on explorer startup sequence.
case WM_WINDOWPOSCHANGING:
{
if(!tray_icon_created) {
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
}
break;
}
default:
if (message == wm_icon_notify) {
switch(lparam) {
@@ -110,7 +124,7 @@ LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam
}
break;
} else if (message == wm_taskbar_restart) {
Shell_NotifyIcon(NIM_ADD, &tray_icon_data);
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
break;
}
}
@@ -154,6 +168,6 @@ void start_tray_icon() {
wcscpy_s(tray_icon_data.szTip, sizeof(tray_icon_data.szTip) / sizeof(WCHAR), L"PowerToys");
tray_icon_data.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
Shell_NotifyIcon(NIM_ADD, &tray_icon_data);
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
}
}

View File

@@ -9,6 +9,8 @@ static std::mutex mutex;
static std::deque<WinHookEvent> hook_events;
static std::condition_variable dispatch_cv;
void intercept_system_menu_action(intptr_t);
static void CALLBACK win_hook_event_proc(HWINEVENTHOOK winEventHook,
DWORD event,
HWND window,
@@ -39,7 +41,9 @@ static void dispatch_thread_proc() {
auto event = hook_events.front();
hook_events.pop_front();
lock.unlock();
powertoys_events().signal_event(win_hook_event, reinterpret_cast<intptr_t>(&event));
intptr_t data = reinterpret_cast<intptr_t>(&event);
intercept_system_menu_action(data);
powertoys_events().signal_event(win_hook_event, data);
lock.lock();
}
}
@@ -70,3 +74,9 @@ void stop_win_hook_event() {
hook_events.shrink_to_fit();
}
void intercept_system_menu_action(intptr_t data) {
WinHookEvent* evt = reinterpret_cast<WinHookEvent*>(data);
if (evt->event == EVENT_SYSTEM_MENUSTART || evt->event == EVENT_OBJECT_INVOKED) {
powertoys_events().handle_system_menu_action(*evt);
}
}

View File

@@ -160,7 +160,12 @@ export class App extends React.Component <any, any> {
},
'i.ms-Button-icon' : {
color: theme.palette.neutralPrimary,
fontWeight: 'normal'
fontWeight: 'normal',
paddingLeft: '5px',
paddingRight: '5px'
},
'.ms-Button-icon > svg' : {
paddingTop: '2px'
},
'&:hover i.ms-Button-icon' : {
color: theme.palette.neutralPrimary,

View File

@@ -30,11 +30,10 @@ export class DropdownSettingsControl extends BaseSettingsControl {
public render(): JSX.Element {
return (
<Dropdown
styles={{
root:{
width: '350px',
alignSelf: 'start'
}}}
styles={{ dropdown: {
width: '350px',
alignSelf: 'start'
} }}
defaultSelectedKey={this.state.property_values.value}
options={this.state.property_values.options}
label={this.state.property_values.display_name}

View File

@@ -191,7 +191,7 @@ export class GeneralSettings extends React.Component <any, any> {
ref={(input) => {this.theme_reference=input;}}
/>
<Stack>
<Label>Version 0.13.0</Label>
<Label>Version {this.state.settings.general.powertoys_version}</Label>
<PrimaryButton
styles={{
root: {

View File

@@ -50,8 +50,7 @@ export class HotkeySettingsControl extends BaseSettingsControl {
// Renders a UI Fabric TextField.
return (
<TextField
styles= {{
root: {
styles={{ fieldGroup: {
width: '350px',
alignSelf: 'start'
}}}
@@ -79,13 +78,7 @@ export class HotkeySettingsControl extends BaseSettingsControl {
new_value.key = '~';
}
if (!new_value.key || new_value.key === 'Unidentified') {
switch (new_value.code) {
case 192:
new_value.key = '~';
break;
default:
new_value.key = `(Key ${new_value.code})`;
}
new_value.key = `(Key ${new_value.code})`;
}
if (new_value.key.length === 1) {
new_value.key = new_value.key.toLocaleUpperCase();

View File

@@ -62,6 +62,7 @@ export class ModuleSettings extends React.Component <any, any> {
<Stack tokens={{childrenGap:20}}>
<Stack>
<Text variant='large'>{this.state.powertoy.description}</Text>
{ this.state.powertoy.hasOwnProperty('overview_link') || this.state.powertoy.hasOwnProperty('video_link') ? <br/> : null }
{
this.state.powertoy.hasOwnProperty('overview_link')
?

View File

@@ -9,7 +9,8 @@ export class StringTextSettingsControl extends BaseSettingsControl {
super(props);
this.textref = null;
this.state={
property_values: props.setting
property_values: props.setting,
multiline: !!props.setting.multiline
}
}
@@ -28,6 +29,10 @@ export class StringTextSettingsControl extends BaseSettingsControl {
// Renders a UI Fabric TextField.
return (
<TextField
styles={{ fieldGroup: {
width: '350px',
alignSelf: 'start'
}}}
onChange = {
(_event,_new_value) => {
// Updates the state with the new value introduced in the TextField.
@@ -42,6 +47,7 @@ export class StringTextSettingsControl extends BaseSettingsControl {
this.parent_on_change();
}
}
multiline={this.state.multiline}
value={this.state.property_values.value}
label={this.state.property_values.display_name}
componentRef= {(input) => {this.textref=input;}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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