Compare commits

..

13 Commits

Author SHA1 Message Date
Leilei Zhang
b545597997 remove the path 2025-10-31 23:47:03 +08:00
Jaylyn Barbee
b995ffabd7 0.95.2 Hotfix (#43087)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Fixes for the light switch module.

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

- [x] Closes: #42878 + another bug that was discovered.
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected

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

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-10-29 15:25:06 -07:00
Kai Tao
3c439eed55 Cursor should not go busy & window should not be active 2025-10-23 16:53:12 +08:00
Jaylyn Barbee
dd33a45aec Light Switch Hotfixes v2 (#42774)
Should fix: #42627
Issue: Suntimes not updating within the day if the mode changes to
SunsetToSunrise
Fix: Update suntimes in the service if the mode is changed to Sun mode.

Other: small bug fixes (brackets, etc)
2025-10-22 12:00:11 -07:00
Copilot
ca6f993be1 Remove WiX v3 infrastructure and migrate exclusively to WiX v5 (#41975)
## Summary:

This pull request refactors the installer build pipeline to simplify and
modernize the process, focusing exclusively on the WiX 5 (VNext)
installer and removing legacy WiX 3 support. It eliminates the use of
the `installerSuffix` parameter and related logic, removes the legacy
installer build steps and scripts, and updates documentation to reflect
the new architecture. The changes streamline the pipeline, reduce
complexity, and ensure only the latest installer is built and signed.

Pipeline and build system simplification:

* Removed the `installerSuffix` parameter and all related logic from
pipeline templates and YAML files, including file naming, build steps,
and hash calculation scripts.
* Removed legacy WiX 3 installer build steps and the associated script
`installWiX.ps1`, focusing exclusively on WiX 5 (VNext) installer
builds.

Installer signing and build process updates:

* Updated `.pipelines/ESRPSigning_installer.json` to remove signing
configuration for the legacy `PowerToysSetupCustomActions.dll`, ensuring
only the VNext DLL is signed.

Documentation updates:

* Updated `doc/devdocs/core/installer.md` to remove references to WiX 3,
clarify the installer architecture as WiX 5 only, and describe the new
build process.

## CheckList:
- [ ] Should Build successfully and produce installer for both per user
and per machine
- [ ] Should install without problem

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vanzue <69313318+vanzue@users.noreply.github.com>
Co-authored-by: Kai Tao (from Dev Box) <kaitao@microsoft.com>
(cherry picked from commit 63da56fae0)
2025-10-22 13:12:10 -05:00
Dustin L. Howett
29687d588f build: run all builds out of a new (huge) P:\ drive (#42739)
The new agents have much smaller temporary disks (which I verified with
another test run to clock in at about 87GB). For right now, let's move
our release builds to a larger drive while we troubleshoot.

(cherry picked from commit 52ce33d438)
2025-10-21 18:32:48 -05:00
Gleb Khmyznikov
6c999c32da 0.95.1 hotfix (#42686)
Hotfixes #42467 #42434 #42405 #42399

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
Co-authored-by: Gordon Lam <73506701+yeelam-gordon@users.noreply.github.com>
Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
2025-10-21 15:16:03 -07:00
vanzue
fd2a3915ef use static link instead of dynamic to solve cmdpal crash 2025-10-15 15:59:03 +08:00
Kai Tao (from Dev Box)
4345b95527 Add new tag to light switch 2025-10-15 15:01:42 +08:00
Shawn Yuan
c0f7ec0265 fixed light switch shortcut not working issue (#42340)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request refactors how the `ToggleThemeHotkey` property is
handled in the LightSwitch settings and view model. The changes simplify
property management by directly referencing the property within
`LightSwitchProperties` and ensure that the hotkey setting is
consistently updated and serialized.

**Settings property management:**

* In `LightSwitchSettings.Clone()`, the `LightSwitchProperties` object
now directly references the existing property instances instead of
creating new ones, and also includes the `ToggleThemeHotkey` property.

**View model property handling:**

* In `LightSwitchViewModel.ToggleThemeActivationShortcut`, the getter
and setter now directly access and update
`ModuleSettings.Properties.ToggleThemeHotkey.Value`, removing the need
for a backing field and ensuring changes are properly serialized and
notified.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

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

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

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

---------

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
(cherry picked from commit 7b9d5af8c1)
2025-10-14 10:49:05 -04:00
leileizhang
c2d1214974 Fix PowerRename crash caused by missing PRI file (#42300)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Not sure why In WinAppSDK 1.8, the default WinUI targets no longer
automatically generate PRI files for unpackaged apps.
By importing the MSIX SDK build tools, the project gains standalone PRI
generation capability.

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

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

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

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-10-11 12:46:52 -07:00
Jiří Polášek
f732185885 CmdPal: Update special fallbacks separately from the other fallbacks (#42289)
## Summary of the Pull Request

This PR introduces a hotfix that updates special fallback items
separately from the rest. This allows the loop handling special fallback
items to finish faster, ensuring they are not delayed by other fallback
items. As a result, calculator and run fallback items will be more
readily available to users.

This partially solves #42286 for special fallback items.

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

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

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

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-10-10 13:01:42 -07:00
Mike Griese
ad207da3f3 CmdPal: make the context menu search look more like a cmdpal (#42081)
Replaces our styling with the same styleing we use for the search bar

But we can't _just_ do that, because the stupid "text cursors don't show
up on top of transparent backgrounds" thing.

So I just added the smoke backdrop to the search box. Seemed reasonable.

Screenshots below.

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2025-10-10 13:01:42 -07:00
621 changed files with 5800 additions and 33184 deletions

View File

@@ -7,13 +7,6 @@ body:
- type: markdown
attributes:
value: Please make sure to [search for existing issues](https://github.com/microsoft/PowerToys/issues) before filing a new one!
- type: markdown
attributes:
value: |
We are aware of the following high-volume issues and are actively working on them. Please check if your issue is one of these before filing a new bug report:
* **PowerToys Run crash related to "Desktop composition is disabled"**: This may appear as `COMException: 0x80263001`. For more details, see issue [#31226](https://github.com/microsoft/PowerToys/issues/31226).
* **PowerToys Run crash with `COMException (0xD0000701)`**: For more details, see issue [#30769](https://github.com/microsoft/PowerToys/issues/30769).
* **PowerToys Run crash with a "Cyclic reference" error**: This `System.InvalidOperationException` is detailed in issue [#36451](https://github.com/microsoft/PowerToys/issues/36451).
- id: version
type: input
attributes:

View File

@@ -321,10 +321,3 @@ REGSTR
# Misc Win32 APIs and PInvokes
INVOKEIDLIST
# PowerRename metadata pattern abbreviations (used in tests and regex patterns)
DDDD
FFF
HHH
riday
YYY

View File

@@ -105,7 +105,6 @@
^src/common/notifications/BackgroundActivatorDLL/cpp\.hint$
^src/common/sysinternals/Eula/
^src/modules/cmdpal/doc/initial-sdk-spec/list-elements-mock-002\.pdn$
^src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage\.cs$
^src/modules/colorPicker/ColorPickerUI/Shaders/GridShader\.cso$
^src/modules/launcher/Plugins/Microsoft\.PowerToys\.Run\.Plugin\.TimeDate/Properties/
^src/modules/MouseUtils/MouseJumpUI/MainForm\.resx$

View File

@@ -2,8 +2,8 @@ AAAAs
abcdefghjkmnpqrstuvxyz
abgr
ABlocked
ABORTIFHUNG
ABOUTBOX
ABORTIFHUNG
Abug
Acceleratorkeys
ACCEPTFILES
@@ -22,7 +22,6 @@ ADate
ADDSTRING
ADDUNDORECORD
ADifferent
adjacents
ADMINS
adml
admx
@@ -35,7 +34,6 @@ AFX
AGGREGATABLE
AHK
AHybrid
AIUI
akv
ALarger
ALIGNRIGHT
@@ -56,7 +54,6 @@ ANull
AOC
aocfnapldcnfbofgmbbllojgocaelgdd
AOklab
aot
APARTMENTTHREADED
APeriod
apicontract
@@ -66,7 +63,6 @@ APIIs
Apm
APPBARDATA
APPEXECLINK
appext
APPLICATIONFRAMEHOST
appmanifest
APPMODEL
@@ -99,9 +95,8 @@ ASYNCWINDOWPLACEMENT
ASYNCWINDOWPOS
atl
ATRIOX
ATX
aumid
authenticode
Authenticode
AUTOBUDDY
AUTOCHECKBOX
AUTOHIDE
@@ -115,10 +110,6 @@ AValid
AWAYMODE
azcliversion
azman
azureaiinference
azureinference
azureopenai
backticks
bbwe
BCIE
bck
@@ -142,7 +133,7 @@ bla
BLACKFRAME
BLENDFUNCTION
Blockquotes
blt
Blt
BLURBEHIND
BLURREGION
bmi
@@ -150,7 +141,6 @@ BNumber
BODGY
BOklab
BOOTSTRAPPERINSTALLFOLDER
Bootstrappers
BOTTOMALIGN
boxmodel
BPBF
@@ -184,10 +174,7 @@ Canvascustomlayout
CAPTUREBLT
CAPTURECHANGED
CARETBLINKING
Carlseibert
CAtl
caub
CBN
cch
CCHDEVICENAME
CCHFORMNAME
@@ -241,7 +228,6 @@ CODENAME
codereview
Codespaces
Coen
cognitiveservices
COINIT
colid
colorconv
@@ -256,12 +242,12 @@ cominterop
commandnotfound
commandpalette
compmgmt
COMPOSITIONDISABLED
COMPOSITIONFULL
CONFIGW
CONFLICTINGMODIFIERKEY
CONFLICTINGMODIFIERSHORTCUT
CONOUT
coreclr
constexpr
contentdialog
contentfiles
@@ -273,7 +259,6 @@ copiedcolorrepresentation
coppied
copyable
COPYPEN
coreclr
COREWINDOW
Corpor
cotaskmem
@@ -284,7 +269,6 @@ cpcontrols
cph
cplusplus
CPower
cppcoreguidelines
cpptools
cppvsdbg
cppwinrt
@@ -293,7 +277,6 @@ CREATEPROCESS
CREATESCHEDULEDTASK
CREATESTRUCT
CREATEWINDOWFAILED
creativecommons
CRECT
CRH
critsec
@@ -313,7 +296,6 @@ CURRENTDIR
CURSORINFO
cursorpos
CURSORSHOWING
CURSORWRAP
customaction
CUSTOMACTIONTEST
CUSTOMFORMATPLACEHOLDER
@@ -329,6 +311,7 @@ CYSCREEN
CYSMICON
CYVIRTUALSCREEN
Czechia
cziplib
Dac
dacl
DAffine
@@ -353,6 +336,7 @@ debugbreak
decryptor
Dedup
Deduplicator
Deeplink
DEFAULTBOOTSTRAPPERINSTALLFOLDER
DEFAULTCOLOR
DEFAULTFLAGS
@@ -385,7 +369,7 @@ devmgmt
DEVMODE
DEVMODEW
devpal
dfx
DFX
DIALOGEX
digicert
DINORMAL
@@ -409,8 +393,6 @@ DNLEN
DONOTROUND
DONTVALIDATEPATH
dotnet
downsampled
downsampling
downscale
DPICHANGED
DPIs
@@ -426,7 +408,7 @@ DROPFILES
DSTINVERT
DString
DSVG
dto
DTo
DUMMYUNIONNAME
dutil
DVASPECT
@@ -460,7 +442,7 @@ EDITKEYBOARD
EDITSHORTCUTS
EDITTEXT
EFile
eku
ekus
emojis
ENABLEDELAYEDEXPANSION
ENABLEDPOPUP
@@ -525,10 +507,8 @@ eyetracker
FANCYZONESDRAWLAYOUTTEST
FANCYZONESEDITOR
FARPROC
fdx
fesf
FFFF
Figma
FILEEXPLORER
fileexploreraddons
fileexplorerpreview
@@ -556,7 +536,6 @@ flac
flyouts
FMask
fmtid
FNumber
FOF
FOFX
FOLDERID
@@ -567,7 +546,6 @@ FORCEMINIMIZE
FORMATDLGORD
formatetc
FORPARSING
foundrylocal
FRAMECHANGED
frm
FROMTOUCH
@@ -586,16 +564,15 @@ gdi
gdiplus
GDIPVER
GDISCALED
geolocator
GETCLIENTAREAANIMATION
GETCURSEL
GETDESKWALLPAPER
GETDLGCODE
GETDPISCALEDSIZE
getfilesiginforedist
geolocator
GETHOTKEY
GETICON
GETLBTEXT
GETMINMAXINFO
GETNONCLIENTMETRICS
GETPROPERTYSTOREFLAGS
@@ -603,19 +580,16 @@ GETSCREENSAVERRUNNING
GETSECKEY
GETSTICKYKEYS
GETTEXTLENGTH
GHND
gitmodules
GHND
GMEM
GNumber
googleai
googlegemini
gpedit
gpo
GPOCA
gpp
gpu
gradians
grctlext
Gridcustomlayout
GSM
gtm
@@ -661,7 +635,6 @@ Hiber
Hiberboot
HIBYTE
hicon
HICONSM
HIDEREADONLY
HIDEWINDOW
Hif
@@ -713,7 +686,6 @@ HTCLIENT
hthumbnail
HTOUCHINPUT
HTTRANSPARENT
hutchinsoniana
HVal
HValue
Hvci
@@ -744,11 +716,9 @@ ietf
IEXPLORE
IFACEMETHOD
IFACEMETHODIMP
ifd
IGNOREUNKNOWN
IGo
iid
IIM
Iindex
Ijwhost
ILD
@@ -772,7 +742,7 @@ INITDIALOG
INITGUID
INITTOLOGFONTSTRUCT
INLINEPREFIX
inlines
Inlines
INPC
inproc
INPUTHARDWARE
@@ -789,6 +759,7 @@ INSTALLFOLDERTOPREVIOUSINSTALLFOLDER
INSTALLLOCATION
INSTALLMESSAGE
INSTALLPROPERTY
installscopeperuser
INSTALLSTARTMENUSHORTCUT
INSTALLSTATE
Inste
@@ -801,7 +772,6 @@ invokecommand
ipcmanager
IPREVIEW
ipreviewhandlervisualssetfont
IPTC
irow
irprops
isbi
@@ -851,8 +821,8 @@ LARGEICON
lastcodeanalysissucceeded
LASTEXITCODE
LAYOUTRTL
lbl
LCh
lbl
lcid
LCIDTo
lcl
@@ -868,10 +838,10 @@ LExit
lhwnd
LIBFUZZER
LIBID
lightswitch
LIMITSIZE
LIMITTEXT
lindex
lightswitch
linkid
LINKOVERLAY
LINQTo
@@ -882,7 +852,6 @@ LLKH
llkhf
LMEM
LMENU
lng
LOADFROMFILE
LOBYTE
localappdata
@@ -892,14 +861,16 @@ LOCATIONCHANGE
LOCKTYPE
LOGFONT
LOGFONTW
LOGMSG
logon
LOGMSG
LOGPIXELSX
LOGPIXELSY
lng
lon
longdate
LONGNAMES
lowlevel
lquadrant
LOWORD
lparam
LPBITMAPINFOHEADER
@@ -933,7 +904,6 @@ lpv
LPW
lpwcx
lpwndpl
lquadrant
LReader
LRESULT
LSTATUS
@@ -951,7 +921,6 @@ LWA
lwin
LZero
MAGTRANSFORM
makeappx
MAKEINTRESOURCE
MAKEINTRESOURCEA
MAKEINTRESOURCEW
@@ -960,7 +929,6 @@ MAKELONG
MAKELPARAM
makepri
MAKEWPARAM
Malware
manifestdependency
MAPPEDTOSAMEKEY
MAPTOSAMESHORTCUT
@@ -983,7 +951,6 @@ MENUITEMINFO
MENUITEMINFOW
MERGECOPY
MERGEPAINT
metadatamatters
Metadatas
metafile
mfc
@@ -1030,6 +997,9 @@ mousepointer
mouseutils
MOVESIZEEND
MOVESIZESTART
muxx
muxxc
muxxh
MRM
MRT
mru
@@ -1049,7 +1019,6 @@ msiexec
MSIFASTINSTALL
MSIHANDLE
MSIRESTARTMANAGERCONTROL
MSIs
msixbundle
MSIXCA
MSLLHOOKSTRUCT
@@ -1058,14 +1027,10 @@ msrc
msstore
msvcp
MT
mstsc
MTND
MULTIPLEUSE
multizone
muxc
muxx
muxxc
muxxh
MVPs
mvvm
MVVMTK
@@ -1176,7 +1141,6 @@ nowarn
NOZORDER
NPH
npmjs
NPU
NResize
NTAPI
ntdll
@@ -1185,7 +1149,6 @@ NTSTATUS
NTSYSAPI
NULLCURSOR
nullonfailure
nullref
numberbox
nwc
ocr
@@ -1201,18 +1164,13 @@ oldpath
oldtheme
oleaut
OLECHAR
ollama
onebranch
onnx
OOBEUI
openas
opencode
OPENFILENAME
openrdp
opensource
openxmlformats
ollama
onnx
OPTIMIZEFORINVOKE
ORPHANEDDIALOGTITLE
ORSCANS
@@ -1285,7 +1243,6 @@ pguid
phbm
phbmp
phicon
Photoshop
phwnd
pici
pidl
@@ -1295,7 +1252,6 @@ pinvoke
pipename
PKBDLLHOOKSTRUCT
pkgfamily
PKI
plib
ploc
ploca
@@ -1404,7 +1360,6 @@ QDC
qit
QITAB
QITABENT
QNN
qoi
Quarternary
QUERYENDSESSION
@@ -1414,8 +1369,8 @@ quickaccent
QUNS
RAII
RAlt
randi
RAquadrant
randi
rasterization
Rasterize
RAWINPUTDEVICE
@@ -1425,8 +1380,6 @@ RAWPATH
rbhid
rclsid
RCZOOMIT
remotedesktop
rdp
RDW
READMODE
READOBJECTS
@@ -1444,7 +1397,9 @@ regfile
REGISTERCLASSFAILED
REGISTRYHEADER
REGISTRYPREVIEWEXT
registryroot
regkey
regroot
regsvr
REINSTALLMODE
releaseblog
@@ -1497,6 +1452,7 @@ rstringalpha
rstringdigit
rtb
RTLREADING
rtm
runas
rundll
rungameid
@@ -1510,7 +1466,6 @@ sacl
safeprojectname
SAMEKEYPREVIOUSLYMAPPED
SAMESHORTCUTPREVIOUSLYMAPPED
samsung
sancov
SAVEFAILED
scanled
@@ -1553,8 +1508,8 @@ SETRULES
SETSCREENSAVEACTIVE
SETSTICKYKEYS
SETTEXT
SETTINGCHANGE
settingscard
SETTINGCHANGE
SETTINGSCHANGED
settingsheader
settingshotkeycontrol
@@ -1699,7 +1654,6 @@ stringtable
stringval
Strm
strret
STRSAFE
stscanf
sttngs
Stubless
@@ -1711,6 +1665,7 @@ sublang
SUBMODULEUPDATE
subresource
Superbar
suntimes
sut
svchost
SVGIn
@@ -1738,12 +1693,12 @@ syskeydown
SYSKEYUP
SYSLIB
SYSMENU
systemai
SYSTEMAPPS
SYSTEMMODAL
SYSTEMTIME
TARG
TARGETAPPHEADER
TARGETDIR
targetentrypoint
TARGETHEADER
targetver
@@ -1773,10 +1728,10 @@ textextractor
TEXTINCLUDE
tfopen
tgz
THEMECHANGED
themeresources
THH
THICKFRAME
THEMECHANGED
THISCOMPONENT
throughs
TILEDWINDOW
@@ -1863,7 +1818,6 @@ UPDATENOW
UPDATEREGISTRY
updown
UPGRADINGPRODUCTCODE
upscaling
Uptool
urld
Usb
@@ -1945,7 +1899,6 @@ Wca
WCE
wcex
WClass
WCRAPI
wcsicmp
wcsncpy
wcsnicmp
@@ -1963,7 +1916,6 @@ wgpocpl
WHEREID
wic
wifi
wikimedia
wikipedia
WIL
winapi
@@ -1977,7 +1929,6 @@ WINDOWPLACEMENT
WINDOWPOSCHANGED
WINDOWPOSCHANGING
WINDOWSBUILDNUMBER
windowsml
windowssearch
windowssettings
WINDOWSTYLES
@@ -1993,7 +1944,6 @@ Winhook
WINL
winlogon
winmd
winml
WINNT
winres
winrt
@@ -2029,7 +1979,7 @@ WORKSPACESEDITOR
WORKSPACESLAUNCHER
WORKSPACESSNAPSHOTTOOL
WORKSPACESWINDOWARRANGER
worktree
Worktree
wox
wparam
wpf
@@ -2056,21 +2006,18 @@ WTSAT
Wubi
WUX
Wwanpp
xap
XAxis
XButton
xclip
xcopy
XDeployment
xdf
XDimension
XDocument
XElement
xfd
XFile
XIncrement
XLoc
xmp
XNamespace
Xoshiro
XPels
@@ -2087,7 +2034,6 @@ XVIRTUALSCREEN
xxxxxx
YAxis
ycombinator
YDimension
YIncrement
yinle
yinyue
@@ -2095,8 +2041,8 @@ YPels
YPos
YResolution
YSpeed
YStr
YTimer
YStr
YVIRTUALSCREEN
ZEROINIT
zonability

View File

@@ -253,7 +253,7 @@ _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
# hit-count: 1 file-count: 1
# Amazon
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)[^"'\s]+
# hit-count: 3 file-count: 3
# imgur

View File

@@ -1,59 +1,43 @@
---
description: PowerToys AI contributor guidance.
applyTo: pullRequests
---
# PowerToys - Copilot guide (concise)
# PowerToys Copilot guide (concise)
This is the top-level guide for AI changes. Keep edits small, follow existing patterns, and cite exact paths in PRs.
# Repo map (1-line per area)
Repo map (1line per area)
- Core apps: `src/runner/**` (tray/loader), `src/settings-ui/**` (Settings app)
- Shared libs: `src/common/**`
- Modules: `src/modules/*` (one per utility; Command Palette in `src/modules/cmdpal/**`)
- Build tools/docs: `tools/**`, `doc/devdocs/**`
# Build and test (defaults)
Build and test (defaults)
- Prerequisites: Visual Studio 2022 17.4+, minimal Windows 10 1803+.
- Build discipline:
- One terminal per operation (build -> test). Do not switch or open new ones mid-flow.
- One terminal per operation (build test). Dont switch/open new ones mid-flow.
- After making changes, `cd` to the project folder that changed (`.csproj`/`.vcxproj`).
- Use scripts to build, synchronously block and wait in foreground for completion: `tools/build/build.ps1|.cmd` (current folder), `build-essentials.*` (once per brand new build for missing nuget packages).
- Treat build exit code 0 as success; any non-zero exit code is a failure. Read the errors log in the build folder (such as `build.*.*.errors.log`) and surface problems.
- Do not start tests or launch Runner until the previous step succeeded.
- Tests (fast and targeted):
- Find the test project by product code prefix (for example FancyZones, AdvancedPaste). Look for a sibling folder or one to two levels up named like `<Product>*UnitTests` or `<Product>*UITests`.
- Build the test project, wait for exit, then run only those tests via VS Test Explorer or `vstest.console.exe` with filters. Avoid `dotnet test` in this repo.
- Add or adjust tests when changing behavior; if skipped, state why (for example comment-only or string rename).
- Use script(s) to build, synchronously block and wait in foreground for it to finish: `tools/build/build.ps1|.cmd` (current folder), `build-essentials.*` (once per brand new build for missing nuget packages)
- Treat build **exit code 0** as success; any non-zero exit code is a failure, have Copilot read the errors log in the build folder (e.g., `build.*.*.errors.log`) and surface problems.
- Dont start tests or launch Runner until the previous step succeeded.
- Tests (fast + targeted):
- Find the test project by product code prefix (e.g., FancyZones, AdvancedPaste). Look for a sibling folder or 12 levels up named like `<Product>*UnitTests` or `<Product>*UITests`.
- Build the test project, wait for **exit**, then run only those tests via VS Test Explorer or `vstest.console.exe` with filters. Avoid `dotnet test` in this repo.
- Add/adjust tests when changing behavior; if skipped, state why (e.g., comment-only, string rename).
# Pull requests (expectations)
- Atomic: one logical change; no drive-by refactors.
- Describe: problem, approach, risk, test evidence.
Pull requests (expectations)
- Atomic: one logical change; no driveby refactors.
- Describe: problem / approach / risk / test evidence.
- List: touched paths if not obvious.
# When to ask for clarification
When to ask for clarification
- Ambiguous spec after scanning relevant docs (see below).
- Cross-module impact (shared enum or struct) not clear.
- Security, elevation, or installer changes.
- Cross-module impact (shared enum/struct) not clear.
- Security / elevation / installer changes.
# Logging (use existing stacks)
- C++ logging lives in `src/common/logger/**` (`Logger::info`, `Logger::warn`, `Logger::error`, `Logger::debug`). Keep hot paths quiet (hooks, tight loops).
- C# logging goes through `ManagedCommon.Logger` (`LogInfo`, `LogWarning`, `LogError`, `LogDebug`, `LogTrace`). Some UIs use injected `ILogger` via `LoggerInstance.Logger`.
Logging (use existing stacks)
- C++: `src/common/logger/**` (`Logger::info|warn|error|debug`). Keep hot paths quiet (hooks, tight loops).
- C#: `ManagedCommon.Logger` (`LogInfo|LogWarning|LogError|LogDebug|LogTrace`). Some UIs use injected `ILogger` via `LoggerInstance.Logger`.
# Docs to consult
Docs to consult
- `tools/build/BUILD-GUIDELINES.md`
- `doc/devdocs/core/architecture.md`
- `doc/devdocs/core/runner.md`
- `doc/devdocs/core/settings/readme.md`
- `doc/devdocs/modules/readme.md`
- `doc/devdocs/core/architecture.md`, `doc/devdocs/core/runner.md`, `doc/devdocs/core/settings/readme.md`, `doc/devdocs/modules/readme.md`
# Language style rules
- Always enforce repo analyzers: root `.editorconfig` plus any `stylecop.json`.
- C# code follows StyleCop.Analyzers and Microsoft.CodeAnalysis.NetAnalyzers.
- C++ code honors `.clang-format` plus `.clang-tidy` (modernize/cppcoreguidelines/readability).
- Markdown files wrap at 80 characters and use ATX headers with fenced code blocks that include language tags.
- YAML files indent two spaces and add comments for complex settings while keeping keys clear.
- PowerShell scripts use Verb-Noun names and prefer single-quoted literals while documenting parameters and satisfying PSScriptAnalyzer.
# Done checklist (self review before finishing)
- Build clean? Tests updated or passed? No unintended formatting? Any new dependency? Documented skips?
Done checklist (self review before finishing)
- Build clean? Tests updated/passed? No unintended formatting? Any new dependency? Documented skips?

View File

@@ -1,16 +0,0 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Generate an 80-character git commit title for the local diff.'
---
**Goal:** Provide a ready-to-paste git commit title (<= 80 characters) that captures the most important local changes since `HEAD`.
**Workflow:**
1. Run a single command to view the local diff since the last commit:
```@terminal
git diff HEAD
```
2. From that diff, identify the dominant area (reference key paths like `src/modules/*`, `doc/devdocs/**`, etc.), the type of change (bug fix, docs update, config tweak), and any notable impact.
3. Draft a concise, imperative commit title summarizing the dominant change. Keep it plain ASCII, <= 80 characters, and avoid trailing punctuation. Mention the primary component when obvious (for example `FancyZones:` or `Docs:`).
4. Respond with only the final commit title on a single line so it can be pasted directly into `git commit`.

View File

@@ -1,22 +0,0 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Generate a PowerToys-ready pull request description from the local diff.'
---
**Goal:** Produce a ready-to-paste PR title and description that follows PowerToys conventions by comparing the current branch against a user-selected target branch.
**Repo guardrails:**
- Treat `.github/pull_request_template.md` as the single source of truth; load it at runtime instead of embedding hardcoded content in this prompt.
- Preserve section order from the template but only surface checklist lines that are relevant for the detected changes, filling them with `[x]`/`[ ]` as appropriate.
- Cite touched paths with inline backticks, matching the guidance in `.github/copilot-instructions.md`.
- Call out test coverage explicitly: list automated tests run (unit/UI) or state why they are not applicable.
**Workflow:**
1. Determine the target branch from user context; default to `main` when no branch is supplied.
2. Run `git status --short` once to surface uncommitted files that may influence the summary.
3. Run `git diff <target-branch>...HEAD` a single time to review the detailed changes. Only when confidence stays low dig deeper with focused calls such as `git diff <target-branch>...HEAD -- <path>`.
4. From the diff, capture impacted areas, key file changes, behavioral risks, migrations, and noteworthy edge cases.
5. Confirm validation: list tests executed with results or state why tests were skipped in line with repo guidance.
6. Load `.github/pull_request_template.md`, mirror its section order, and populate it with the gathered facts. Include only relevant checklist entries, marking them `[x]/[ ]` and noting any intentional omissions as "N/A".
7. Present the filled template inside a fenced ```markdown code block with no extra commentary so it is ready to paste into a PR, clearly flagging any placeholders that still need user input.

View File

@@ -1,22 +0,0 @@
---
mode: 'agent'
model: GPT-5-Codex (Preview)
description: 'Resolve Code scanning / check-spelling comments on the active PR.'
---
**Goal:** Clear every outstanding GitHub pull request comment created by the `Code scanning / check-spelling` workflow by explicitly allowing intentional terms.
**Guardrails:**
- Update only discussion threads authored by `github-actions` or `github-actions[bot]` that mention `Code scanning results / check-spelling`.
- Resolve findings solely by editing `.github/actions/spell-check/expect.txt`; reuse existing entries.
- Leave all other files and topics untouched.
**Prerequisites:**
- Install GitHub CLI if it is not present: `winget install GitHub.cli`.
- Run `gh auth login` once before the first CLI use.
**Workflow:**
1. Determine the active pull request with a single `gh pr view --json number` call (default to the current branch).
2. Fetch all PR discussion data once via `gh pr view --json comments,reviews` and filter to check-spelling comments authored by `github-actions` or `github-actions[bot]` that are not minimized; when several remain, process only the most recent comment body.
3. For each flagged token, review `.github/actions/spell-check/expect.txt` for an equivalent term (for example an existing lowercase variant); when found, reuse that normalized term rather than adding a new entry, even if the flagged token differs only by casing. Only add a new entry after confirming no equivalent already exists.
4. Add any remaining missing token to `.github/actions/spell-check/expect.txt`, keeping surrounding formatting intact.

View File

@@ -5,7 +5,6 @@
## PR Checklist
- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) -->
- [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized

View File

@@ -21,6 +21,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4

View File

@@ -27,7 +27,7 @@ jobs:
issue: ${{ fromJson(github.event.inputs.issue_numbers) }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v3
- name: Run GenAI Issue Deduplicator
uses: pelikhan/action-genai-issue-dedup@v0

View File

@@ -40,7 +40,7 @@ jobs:
echo powerToysInstallerArm64Url=$(jq -n "$powerToysSetup" | jq -r '[.[]|select(.name | contains("arm64"))][0].browser_download_url') >> $GITHUB_OUTPUT
- name: Setup .NET 9.0
uses: actions/setup-dotnet@v5
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'

3
.gitignore vendored
View File

@@ -349,7 +349,10 @@ src/common/Telemetry/*.etl
/src/modules/powerrename/ui/RCb24464
# Generated installer file for Monaco source files.
/installer/PowerToysSetup/MonacoSRC.wxs
/installer/PowerToysSetup/DscResources.wxs
/installer/PowerToysSetupVNext/MonacoSRC.wxs
/installer/PowerToysSetupVNext/DscResources.wxs
# MSBuildCache
/MSBuildCacheLogs/

3
.gitmodules vendored
View File

@@ -4,3 +4,6 @@
[submodule "deps/expected-lite"]
path = deps/expected-lite
url = https://github.com/martinmoene/expected-lite.git
[submodule "deps/cziplib"]
path = deps/cziplib
url = https://github.com/kuba--/zip.git

View File

@@ -5,6 +5,7 @@
{
"MatchedPath": [
"*.resources.dll",
"WinUI3Apps\\Assets\\Settings\\Scripts\\*.ps1",
"PowerToys.ActionRunner.exe",
@@ -26,7 +27,6 @@
"PowerToys.GPOWrapper.dll",
"PowerToys.GPOWrapperProjection.dll",
"PowerToys.AllExperiments.dll",
"LanguageModelProvider.dll",
"Common.Search.dll",
@@ -181,7 +181,6 @@
"PowerToys.MousePointerCrosshairs.dll",
"PowerToys.MouseJumpUI.dll",
"PowerToys.MouseJumpUI.exe",
"PowerToys.CursorWrap.dll",
"PowerToys.MouseWithoutBorders.dll",
"PowerToys.MouseWithoutBorders.exe",
@@ -236,9 +235,7 @@
"*Microsoft.CmdPal.UI_*.msix",
"PowerToys.DSC.dll",
"PowerToys.DSC.exe",
"PowerToysSparse.msix"
"PowerToys.DSC.exe"
],
"SigningInfo": {
"Operations": [
@@ -291,7 +288,6 @@
"Mono.Cecil.Rocks.dll",
"Newtonsoft.Json.dll",
"CommunityToolkit.WinUI.Controls.TitleBar.dll",
"CommunityToolkit.WinUI.Controls.OpacityMaskView.dll",
"NLog.dll",
"HtmlAgilityPack.dll",
@@ -348,8 +344,6 @@
"Testably.Abstractions.FileSystem.Interface.dll",
"WinUI3Apps\\Testably.Abstractions.FileSystem.Interface.dll",
"ColorCode.Core.dll",
"Microsoft.SemanticKernel.Connectors.Ollama.dll",
"OllamaSharp.dll",
"UnitsNet.dll",
"UtfUnknown.dll",

View File

@@ -0,0 +1,53 @@
{
"Version": "1.0.0",
"UseMinimatch": false,
"SignBatches": [
{
"MatchedPath": [
"PowerToysSetupCustomActionsVNext.dll",
"SilentFilesInUseBAFunction.dll",
"PowerToys*Setup-*.exe",
"PowerToys*Setup-*.msi"
],
"SigningInfo": {
"Operations": [
{
"KeyCode": "CP-230012",
"OperationSetCode": "SigntoolSign",
"Parameters": [
{
"parameterName": "OpusName",
"parameterValue": "Microsoft"
},
{
"parameterName": "OpusInfo",
"parameterValue": "http://www.microsoft.com"
},
{
"parameterName": "FileDigest",
"parameterValue": "/fd \"SHA256\""
},
{
"parameterName": "PageHash",
"parameterValue": "/NPH"
},
{
"parameterName": "TimeStamp",
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
}
],
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationSetCode": "SigntoolVerify",
"Parameters": [],
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
}
}
]
}

View File

@@ -65,28 +65,21 @@ if (-not (Test-Path $outputDir)) {
New-Item -Path $outputDir -ItemType Directory -Force | Out-Null
}
# DSC v3 manifests go to DSCModules subfolder
$dscOutputDir = Join-Path $outputDir 'DSCModules'
if (-not (Test-Path $dscOutputDir)) {
Write-Host "Creating DSCModules subfolder at '$dscOutputDir'."
New-Item -Path $dscOutputDir -ItemType Directory -Force | Out-Null
}
Write-Host "DSC manifests will be generated to: '$outputDir'"
Write-Host "DSC manifests will be generated to: '$dscOutputDir'"
Write-Host "Cleaning previously generated DSC manifest files from '$outputDir'."
Get-ChildItem -Path $outputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction SilentlyContinue | Remove-Item -Force
Write-Host "Cleaning previously generated DSC manifest files from '$dscOutputDir'."
Get-ChildItem -Path $dscOutputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction SilentlyContinue | Remove-Item -Force
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $dscOutputDir)
$arguments = @('manifest', '--resource', 'settings', '--outputDir', $outputDir)
Write-Host "Invoking DSC manifest generator: '$exePath' $($arguments -join ' ')"
& $exePath @arguments
if ($LASTEXITCODE -ne 0) {
throw "PowerToys.DSC.exe exited with code $LASTEXITCODE"
}
$generatedFiles = Get-ChildItem -Path $dscOutputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction Stop
$generatedFiles = Get-ChildItem -Path $outputDir -Filter 'microsoft.powertoys.*.settings.dsc.resource.json' -ErrorAction Stop
if ($generatedFiles.Count -eq 0) {
throw "No DSC manifest files were generated in '$dscOutputDir'."
throw "No DSC manifest files were generated in '$outputDir'."
}
Write-Host "Generated $($generatedFiles.Count) DSC manifest file(s):"

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.PowerToys.Telemetry" version="2.0.4" />
<package id="Microsoft.PowerToys.Telemetry" version="2.0.3" />
</packages>

View File

@@ -32,7 +32,7 @@ parameters:
- name: enableMsBuildCaching
type: boolean
displayName: "Enable MSBuild Caching"
default: false
default: true
- name: runTests
type: boolean
displayName: "Run Tests"

View File

@@ -52,6 +52,8 @@ extends:
name: SHINE-INT-S
${{ if eq(parameters.useVSPreview, true) }}:
demands: ImageOverride -equals SHINE-VS17-Preview
${{ else }}:
image: SHINE-VS17-Latest
os: windows
sdl:
tsa:
@@ -73,6 +75,7 @@ extends:
name: SHINE-INT-L
demands:
# Our INT agents have a large disk mounted at P:\
- WorkFolder -equals P:\_work
- ${{ if eq(parameters.useVSPreview, true) }}:
- ImageOverride -equals SHINE-VS17-Preview
os: windows
@@ -123,6 +126,7 @@ extends:
parameters:
pool:
name: SHINE-INT-L
image: SHINE-VS17-Latest
os: windows
official: true
codeSign: true

View File

@@ -111,7 +111,6 @@ jobs:
${{ else }}:
OutputBuildPlatform: ${{ platform }}
variables:
NUGET_PACKAGES: 'C:\NuGetPackages' # Some of our build steps cache these here... and it was apparently part of the global environment
MakeAppxPath: 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\MakeAppx.exe'
# Azure DevOps abhors a vacuum
# If these are blank, expansion will fail later on... which will result in direct substitution of the variable *names*
@@ -140,10 +139,6 @@ jobs:
- output: pipelineArtifact
artifactName: $(JobOutputArtifactName)
targetPath: $(Build.ArtifactStagingDirectory)
- output: pipelineArtifact
artifactName: $(JobOutputArtifactName)-failure-$(System.JobAttempt)
targetPath: $(LogOutputDirectory)
condition: or(failed(), canceled())
steps:
- checkout: self
clean: true
@@ -271,26 +266,6 @@ jobs:
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: VSBuild@1
displayName: Generate DSC artifacts for ARM64
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
inputs:
solution: PowerToys.sln
vsVersion: 17.0
msbuildArgs: >-
-restore
/p:Configuration=$(BuildConfiguration)
/p:Platform=x64
/t:DSC\PowerToys_Settings_DSC_Schema_Generator
/bl:$(LogOutputDirectory)\build-dsc-generator.binlog
${{ parameters.additionalBuildOptions }}
$(MSBuildCacheParameters)
$(RestoreAdditionalProjectSourcesArg)
platform: x64
configuration: $(BuildConfiguration)
msbuildArchitecture: x64
maximumCpuCount: true
# Build PowerToys.DSC.exe for ARM64 (x64 uses existing binary from previous build)
- task: VSBuild@1
displayName: Build PowerToys.DSC.exe (x64 for generating manifests)
@@ -400,7 +375,7 @@ jobs:
### HACK: On ARM64 builds, building an app with Windows App SDK copies the x64 WebView2 dll instead of the ARM64 one. This task makes sure the right dll is used.
- task: CopyFiles@2
displayName: HACK Copy core WebView2 ARM64 dll to output directory
condition: and(succeeded(), eq(variables['BuildPlatform'], 'arm64'))
condition: eq(variables['BuildPlatform'],'arm64')
inputs:
contents: packages/Microsoft.Web.WebView2.1.0.2903.40/runtimes/win-ARM64/native_uap/Microsoft.Web.WebView2.Core.dll
targetFolder: $(Build.SourcesDirectory)/ARM64/Release/WinUI3Apps/
@@ -439,11 +414,11 @@ jobs:
inputs:
testResultsFormat: VSTest
testResultsFiles: '**/*.trx'
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
condition: ne(variables['BuildPlatform'],'arm64')
# Native dlls
- task: VSTest@2
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64')) # No arm64 agents to run the tests.
condition: ne(variables['BuildPlatform'],'arm64') # No arm64 agents to run the tests.
displayName: 'Native Tests'
inputs:
platform: '$(BuildPlatform)'
@@ -537,6 +512,14 @@ jobs:
versionNumber: ${{ parameters.versionNumber }}
additionalBuildOptions: ${{ parameters.additionalBuildOptions }}
- template: steps-build-installer-vnext.yml
parameters:
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
versionNumber: ${{ parameters.versionNumber }}
additionalBuildOptions: ${{ parameters.additionalBuildOptions }}
buildUserInstaller: true # NOTE: This is the distinction between the above and below rules
# This saves ~1GiB per architecture. We won't need these later.
# Removes:
# - All .pdb files from any static libs .libs (which were only used during linking)

View File

@@ -2,6 +2,9 @@ parameters:
- name: versionNumber
type: string
default: "0.0.1"
- name: buildUserInstaller
type: boolean
default: false
- name: codeSign
type: boolean
default: false
@@ -22,26 +25,43 @@ steps:
arguments: 'install --global wix --version 5.0.2'
- pwsh: |-
Write-Host "##vso[task.setvariable variable=InstallerMachineRoot]installer\PowerToysSetupVNext\$(BuildPlatform)\$(BuildConfiguration)\MachineSetup"
Write-Host "##vso[task.setvariable variable=InstallerUserRoot]installer\PowerToysSetupVNext\$(BuildPlatform)\$(BuildConfiguration)\UserSetup"
Write-Host "##vso[task.setvariable variable=InstallerMachineBasename]PowerToysSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
Write-Host "##vso[task.setvariable variable=InstallerUserBasename]PowerToysUserSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
displayName: Prepare Installer variables
& git clean -xfd -e *exe -- .\installer\
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Clean installer to reduce cross-contamination
- pwsh: |-
# Determine whether this is a per-user build
$IsPerUser = $${{ parameters.buildUserInstaller }}
# Build slug used to locate the artifacts
$InstallerBuildSlug = if ($IsPerUser) { 'UserSetup' } else { 'MachineSetup' }
# VNext bundle folder; base name intentionally omits the VNext suffix
$InstallerFolder = 'PowerToysSetupVNext'
if ($IsPerUser) {
$InstallerBasename = "PowerToysUserSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
}
else {
$InstallerBasename = "PowerToysSetup-${{ parameters.versionNumber }}-$(BuildPlatform)"
}
# Export variables for downstream steps
Write-Host "##vso[task.setvariable variable=InstallerBuildSlug]$InstallerBuildSlug"
Write-Host "##vso[task.setvariable variable=InstallerRelativePath]$(BuildPlatform)\$(BuildConfiguration)\$InstallerBuildSlug"
Write-Host "##vso[task.setvariable variable=InstallerBasename]$InstallerBasename"
Write-Host "##vso[task.setvariable variable=InstallerFolder]$InstallerFolder"
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Prepare Installer variables
# This dll needs to be built and signed before building the MSI.
# The Custom Actions project contains a pre-build event that prepares the .wxs files
# by filling them out with all our components. We pass RunBuildEvents=true to force
# that logic to run.
- task: VSBuild@1
displayName: Build Shared Support DLLs
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build PowerToysSetupCustomActionsVNext
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysSetupCustomActionsVNext;SilentFilesInUseBAFunction
/p:RunBuildEvents=true;RestorePackagesConfig=true;CIBuild=true
/t:PowerToysSetupCustomActionsVNext
/p:RunBuildEvents=true;PerUser=${{parameters.buildUserInstaller}};RestorePackagesConfig=true;CIBuild=true
-restore -graph
/bl:$(LogOutputDirectory)\installer-actions.binlog
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-actions.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -50,53 +70,28 @@ steps:
maximumCpuCount: true
- ${{ if eq(parameters.codeSign, true) }}:
- template: steps-esrp-sign-files-authenticode.yml
- template: steps-esrp-signing.yml
parameters:
displayName: Sign Shared Support DLLs
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign PowerToysSetupCustomActionsVNext
signingIdentity: ${{ parameters.signingIdentity }}
folder: 'installer'
pattern: |-
**/PowerToysSetupCustomActionsVNext.dll
**/SilentFilesInUseBAFunction.dll
inputs:
FolderPath: 'installer/PowerToysSetupCustomActionsVNext/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
## INSTALLER START
#### MSI BUILDING AND SIGNING
#
# The MSI build contains code that reverts the .wxs files to their in-tree versions.
# This is only supposed to happen during local builds. Since this build system is
# supposed to run side by side--machine and then user--we do NOT want to destroy
# the .wxs files. Therefore, we pass RunBuildEvents=false to suppress all of that
# logic.
#
# We pass BuildProjectReferences=false so that it does not recompile the DLLs we just built.
# We only pass -restore on the first one because the second run should already have all
# of the dependencies.
- task: VSBuild@1
displayName: 💻 Build VNext MSI
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext MSI
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
-restore
/t:PowerToysInstallerVNext
/p:RunBuildEvents=false;PerUser=false;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-machine-msi.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the CustomActions dll
msbuildArchitecture: x64
maximumCpuCount: true
- task: VSBuild@1
displayName: 👤 Build VNext MSI
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysInstallerVNext
/p:RunBuildEvents=false;PerUser=true;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-user-msi.binlog
/p:RunBuildEvents=false;PerUser=${{parameters.buildUserInstaller}};BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-msi.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -105,66 +100,77 @@ steps:
maximumCpuCount: true
- script: |-
wix msi decompile $(InstallerMachineRoot)\$(InstallerMachineBasename).msi -x $(build.sourcesdirectory)\extractedMachineMsi
wix msi decompile $(InstallerUserRoot)\$(InstallerUserBasename).msi -x $(build.sourcesdirectory)\extractedUserMsi
dir $(build.sourcesdirectory)\extractedMachineMsi
dir $(build.sourcesdirectory)\extractedUserMsi
displayName: "WiX5: Extract and verify MSIs"
wix msi decompile installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).msi -x $(build.sourcesdirectory)\extractedMsi
dir $(build.sourcesdirectory)\extractedMsi
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Extract and verify MSI"
# Check if deps.json files don't reference different dll versions.
- pwsh: |-
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\File'
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedUserMsi\File'
displayName: Audit deps.json in MSI extracted files
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\extractedMsi\File'
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Audit deps.json in MSI extracted files
- ${{ if eq(parameters.codeSign, true) }}:
- pwsh: |-
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMachineMsi\Binary'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedUserMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedUserMsi\Binary'
git clean -xfd ./extractedMachineMsi ./extractedUserMsi
displayName: Verify all binaries are signed and versioned
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMsi\File'
& .pipelines/versionAndSignCheck.ps1 -targetDir '$(build.sourcesdirectory)\extractedMsi\Binary'
git clean -xfd ./extractedMsi
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Verify all binaries are signed and versioned
- template: steps-esrp-sign-files-authenticode.yml
- template: steps-esrp-signing.yml
parameters:
displayName: Sign VNext MSIs
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign VNext MSI
signingIdentity: ${{ parameters.signingIdentity }}
folder: 'installer'
pattern: '**/PowerToys*Setup-*.msi'
inputs:
FolderPath: 'installer/$(InstallerFolder)/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
#### END MSI
#### BOOTSTRAP BUILDING AND SIGNING
# We pass BuildProjectReferences=false so that it does not recompile the DLLs we just built.
# We only pass -restore on the first one because the second run should already have all
# of the dependencies.
#### BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
- task: VSBuild@1
displayName: 💻 Build VNext Bootstrapper
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build SilentFilesInUseBAFunction
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:SilentFilesInUseBAFunction
/p:RunBuildEvents=true;PerUser=${{parameters.buildUserInstaller}};RestorePackagesConfig=true;CIBuild=true
-restore -graph
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-SilentFilesInUseBAFunction.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the msi
msbuildArchitecture: x64
maximumCpuCount: true
- ${{ if eq(parameters.codeSign, true) }}:
- template: steps-esrp-signing.yml
parameters:
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign SilentFilesInUseBAFunction
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: 'installer/$(BuildPlatform)/$(BuildConfiguration)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
#### END BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
#### BOOTSTRAP BUILDING AND SIGNING
- task: VSBuild@1
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext Bootstrapper
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
-restore
/t:PowerToysBootstrapperVNext
/p:PerUser=false;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-machine-bootstrapper.binlog
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: false # don't undo our hard work above by deleting the MSI nor SilentFilesInUseBAFunction
msbuildArchitecture: x64
maximumCpuCount: true
- task: VSBuild@1
displayName: 👤 Build VNext Bootstrapper
inputs:
solution: "**/installer/PowerToysSetup.sln"
vsVersion: 17.0
msbuildArgs: >-
/t:PowerToysBootstrapperVNext
/p:PerUser=true;BuildProjectReferences=false;CIBuild=true
/bl:$(LogOutputDirectory)\installer-user-bootstrapper.binlog
/p:PerUser=${{parameters.buildUserInstaller}};CIBuild=true
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-bootstrapper.binlog
-restore -graph
${{ parameters.additionalBuildOptions }}
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -175,41 +181,54 @@ steps:
# The entirety of bundle unpacking/re-packing is unnecessary if we are not code signing it.
- ${{ if eq(parameters.codeSign, true) }}:
- script: |-
wix burn detach $(InstallerMachineRoot)\$(InstallerMachineBasename).exe -engine installer\machine-engine.exe
wix burn detach $(InstallerUserRoot)\$(InstallerUserBasename).exe -engine installer\user-engine.exe
displayName: "WiX5: Extract Engines from Bundles"
wix burn detach installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Extract Engine from Bundle"
- template: steps-esrp-sign-files-authenticode.yml
- template: steps-esrp-signing.yml
parameters:
displayName: Sign WiX Engines
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign WiX Engine
signingIdentity: ${{ parameters.signingIdentity }}
folder: "installer"
pattern: '*-engine.exe'
inputs:
FolderPath: "installer"
Pattern: engine.exe
signConfigType: inlineSignParams
inlineOperation: |
[
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"PageHash": "/NPH",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
- script: |-
wix burn reattach $(InstallerMachineRoot)\$(InstallerMachineBasename).exe -engine installer\machine-engine.exe -o $(InstallerMachineRoot)\$(InstallerMachineBasename).exe
wix burn reattach $(InstallerUserRoot)\$(InstallerUserBasename).exe -engine installer\user-engine.exe -o $(InstallerUserRoot)\$(InstallerUserBasename).exe
displayName: "WiX5: Reattach Engines to Bundles"
wix burn reattach installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe -o installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe
displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Reattach Engine to Bundle"
- pwsh: |-
& wix burn extract -oba installer\ba\m "$(InstallerMachineRoot)\$(InstallerMachineBasename).exe"
& wix burn extract -oba installer\ba\u "$(InstallerUserRoot)\$(InstallerUserBasename).exe"
Get-ChildItem installer\ba -Recurse -Include *.exe,*.dll | Get-AuthenticodeSignature | ForEach-Object {
If ($_.Status -Ne "Valid") {
Write-Error $_.StatusMessage
} Else {
Write-Host $_.StatusMessage
}
}
& git clean -fdx installer\ba
displayName: "WiX5: Verify Bootstrapper content is signed"
- template: steps-esrp-sign-files-authenticode.yml
- template: steps-esrp-signing.yml
parameters:
displayName: Sign Final Bootstrappers
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign Final Bootstrapper
signingIdentity: ${{ parameters.signingIdentity }}
folder: 'installer'
pattern: '**/PowerToys*Setup-*.exe'
inputs:
FolderPath: 'installer/$(InstallerFolder)/$(InstallerRelativePath)'
signType: batchSigning
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
#### END BOOTSTRAP
## END INSTALLER

View File

@@ -1,45 +0,0 @@
parameters:
- name: displayName
type: string
default: Sign Specific Files
- name: folder
type: string
- name: pattern
type: string
- name: signingIdentity
type: object
default: {}
steps:
- template: steps-esrp-signing.yml
parameters:
displayName: ${{ parameters.displayName }}
signingIdentity: ${{ parameters.signingIdentity }}
inputs:
FolderPath: ${{ parameters.folder }}
Pattern: ${{ parameters.pattern }}
UseMinimatch: true
signConfigType: inlineSignParams
inlineOperation: |-
[
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"PageHash": "/NPH",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"KeyCode": "CP-230012",
"OperationCode": "SigntoolVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]

13
.vscode/launch.json vendored
View File

@@ -38,17 +38,6 @@
"env": {},
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": "Run AdvancedPaste (managed, no build, ARCH configurable)",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}\\${input:arch}\\Debug\\WinUI3Apps\\PowerToys.AdvancedPaste.exe",
"args": [],
"cwd": "${workspaceFolder}",
"env": {},
"console": "internalConsole",
"stopAtEntry": false
},
}
]
}

View File

@@ -26,7 +26,6 @@
<PropertyGroup Condition="'$(SkipCppCodeAnalysis)' == ''">
<RunCodeAnalysis>true</RunCodeAnalysis>
<CodeAnalysisRuleSet>$(MsbuildThisFileDirectory)\CppRuleSet.ruleset</CodeAnalysisRuleSet>
<CAExcludePath>$(MSBuildThisFileDirectory)deps;$(MSBuildThisFileDirectory)packages;$(CAExcludePath)</CAExcludePath>
</PropertyGroup>
<!-- C++ source compile-specific things for all configurations -->
@@ -35,7 +34,7 @@
<PreferredToolArchitecture Condition="'$(PROCESSOR_ARCHITECTURE)' == 'ARM64' or '$(PROCESSOR_ARCHITEW6432)' == 'ARM64'">arm64</PreferredToolArchitecture>
<VcpkgEnabled>false</VcpkgEnabled>
<ReplaceWildcardsInProjectItems>true</ReplaceWildcardsInProjectItems>
<ExternalIncludePath>$(MSBuildThisFileDirectory)deps;$(MSBuildThisFileDirectory)packages;$(ExternalIncludePath)</ExternalIncludePath>
<ExternalIncludePath>$(MSBuildThisFileFullPath)\..\deps\;$(MSBuildThisFileFullPath)\..\packages\;$(ExternalIncludePath)</ExternalIncludePath>
<!-- Enable control flow guard for C++ projects that don't consume any C++ files -->
<!-- This covers the case where a .dll exports a .lib, but doesn't have any ClCompile entries. -->
<LinkControlFlowGuard>Guard</LinkControlFlowGuard>

View File

@@ -147,18 +147,6 @@ _If you want to find diagnostic data events in the source code, these two links
<td>Microsoft.PowerToys.AdvancedPasteSemanticKernelFormatEvent</td>
<td>Triggered when Advanced Paste leverages the Semantic Kernel.</td>
</tr>
<tr>
<td>Microsoft.PowerToys.AdvancedPasteSemanticKernelErrorEvent</td>
<td>Occurs when the Semantic Kernel workflow encounters an error.</td>
</tr>
<tr>
<td>Microsoft.PowerToys.AdvancedPasteEndpointUsageEvent</td>
<td>Logs the AI provider, model, and processing duration for each endpoint call.</td>
</tr>
<tr>
<td>Microsoft.PowerToys.AdvancedPasteCustomActionErrorEvent</td>
<td>Records provider, model, and status details when a custom action fails.</td>
</tr>
</table>
### Always on Top

View File

@@ -1,4 +1,4 @@
<Project>
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
@@ -7,9 +7,9 @@
<PackageVersion Include="AdaptiveCards.ObjectModel.WinUI3" Version="2.0.0-beta" />
<PackageVersion Include="AdaptiveCards.Rendering.WinUI3" Version="2.1.0-beta" />
<PackageVersion Include="AdaptiveCards.Templating" Version="2.0.5" />
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.OpacityMaskView" Version="0.1.251101-build.2372" />
<PackageVersion Include="Microsoft.Bot.AdaptiveExpressions.Core" Version="4.23.0" />
<PackageVersion Include="Appium.WebDriver" Version="4.4.5" />
<PackageVersion Include="Azure.AI.OpenAI" Version="1.0.0-beta.17" />
<PackageVersion Include="CoenM.ImageSharp.ImageHash" Version="1.3.6" />
<PackageVersion Include="CommunityToolkit.Common" Version="8.4.0" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
@@ -35,33 +35,23 @@
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
<PackageVersion Include="MessagePack" Version="3.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.10" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.8" />
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.8" />
<PackageVersion Include="Microsoft.Windows.CppWinRT" Version="2.0.240111.5" />
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.16" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="9.9.1" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="9.9.1-preview.1.25474.6" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.10" />
<PackageVersion Include="Microsoft.AI.Foundry.Local" Version="0.3.0" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.66.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.66.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.AzureAIInference" Version="1.66.0-beta" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.MistralAI" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.8" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.15.0" />
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.10" />
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.8" />
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.10" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.8" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.3.183" />
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. -->
<!--
@@ -69,10 +59,8 @@
This is present due to a bug in CsWinRT where WPF projects cause the analyzer to fail.
-->
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6901" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4948" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250907003" />
<PackageVersion Include="Microsoft.WindowsAppSDK.AI" Version="1.8.37" />
<PackageVersion Include="Microsoft.WindowsAppSDK.Runtime" Version="1.8.250907003" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />
@@ -84,7 +72,7 @@
<PackageVersion Include="NLog" Version="5.2.8" />
<PackageVersion Include="NLog.Extensions.Logging" Version="5.3.8" />
<PackageVersion Include="NLog.Schema" Version="5.2.8" />
<PackageVersion Include="OpenAI" Version="2.5.0" />
<PackageVersion Include="OpenAI" Version="2.0.0" />
<PackageVersion Include="ReverseMarkdown" Version="4.1.0" />
<PackageVersion Include="RtfPipe" Version="2.0.7677.4303" />
<PackageVersion Include="ScipBe.Common.Office.OneNote" Version="3.0.1" />
@@ -94,29 +82,28 @@
<PackageVersion Include="StreamJsonRpc" Version="2.21.69" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<!-- Package System.CodeDom added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Management but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="System.CodeDom" Version="9.0.10" />
<PackageVersion Include="System.CodeDom" Version="9.0.8" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.10" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.10" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.10" />
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.8" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.8" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.8" />
<!-- Package System.Data.SqlClient added to force it as a dependency of Microsoft.Windows.Compatibility to the latest version available at this time. -->
<PackageVersion Include="System.Data.SqlClient" Version="4.9.0" />
<!-- Package System.Diagnostics.EventLog added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Data.OleDb but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.10" />
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.8" />
<!-- Package System.Diagnostics.PerformanceCounter added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.11. -->
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.10" />
<PackageVersion Include="System.ClientModel" Version="1.7.0" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.10" />
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.8" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.8" />
<PackageVersion Include="System.IO.Abstractions" Version="22.0.13" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.13" />
<PackageVersion Include="System.Management" Version="9.0.10" />
<PackageVersion Include="System.Management" Version="9.0.8" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<PackageVersion Include="System.Reactive" Version="6.0.1" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.10" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.10" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.10" />
<PackageVersion Include="System.Text.Json" Version="9.0.10" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.8" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.8" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.8" />
<PackageVersion Include="System.Text.Json" Version="9.0.8" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />
<PackageVersion Include="UnitsNet" Version="5.56.0" />
@@ -138,4 +125,4 @@
<PackageVersion Include="Microsoft.VariantAssignment.Client" Version="2.4.17140001" />
<PackageVersion Include="Microsoft.VariantAssignment.Contract" Version="3.0.16990001" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1495,10 +1495,10 @@ SOFTWARE.
- AdaptiveCards.Rendering.WinUI3
- AdaptiveCards.Templating
- Appium.WebDriver
- Azure.AI.OpenAI
- CoenM.ImageSharp.ImageHash
- CommunityToolkit.Common
- CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock
- CommunityToolkit.Labs.WinUI.Controls.OpacityMaskView
- CommunityToolkit.Mvvm
- CommunityToolkit.WinUI.Animations
- CommunityToolkit.WinUI.Collections

View File

@@ -26,7 +26,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D} = {D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}
{D940E07F-532C-4FF3-883F-790DA014F19A} = {D940E07F-532C-4FF3-883F-790DA014F19A}
{DA425894-6E13-404F-8DCB-78584EC0557A} = {DA425894-6E13-404F-8DCB-78584EC0557A}
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D} = {E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}
{E364F67B-BB12-4E91-B639-355866EBCD8B} = {E364F67B-BB12-4E91-B639-355866EBCD8B}
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
EndProjectSection
@@ -51,8 +50,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{1AFB64
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common.Lib.UnitTests", "src\common\UnitTests-CommonLib\UnitTests-CommonLib.vcxproj", "{1A066C63-64B3-45F8-92FE-664E1CCE8077}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PackageIdentity", "src\PackageIdentity\PackageIdentity.vcxproj", "{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FancyZonesEditor", "src\modules\fancyzones\editor\FancyZonesEditor\FancyZonesEditor.csproj", "{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "powerrename", "powerrename", "{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}"
@@ -822,22 +819,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSea
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Shell.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Shell.UnitTests\Microsoft.CmdPal.Ext.Shell.UnitTests.csproj", "{E816D7B4-4688-4ECB-97CC-3D8E798F3833}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CursorWrap", "src\modules\MouseUtils\CursorWrap\CursorWrap.vcxproj", "{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3DCCD936-D085-4869-A1DE-CA6A64152C94}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightSwitch.UITests", "src\modules\LightSwitch\Tests\LightSwitch.UITests\LightSwitch.UITests.csproj", "{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests\Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests.csproj", "{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LanguageModelProvider", "src\common\LanguageModelProvider\LanguageModelProvider.csproj", "{45354F4F-1414-45CE-B600-51CD1209FD19}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.UI.ViewModels.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.UI.ViewModels.UnitTests\Microsoft.CmdPal.UI.ViewModels.UnitTests.csproj", "{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.RemoteDesktop", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.RemoteDesktop\Microsoft.CmdPal.Ext.RemoteDesktop.csproj", "{2B3FB837-23DE-629F-82C6-42304E7083C9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests\Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests.csproj", "{DB34808A-FF91-D06E-A426-AFB5A8BD583B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -878,14 +867,6 @@ Global
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|ARM64.Build.0 = Release|ARM64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.ActiveCfg = Release|x64
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.Build.0 = Release|x64
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}.Debug|ARM64.Build.0 = Debug|ARM64
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}.Debug|x64.ActiveCfg = Debug|x64
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}.Debug|x64.Build.0 = Debug|x64
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}.Release|ARM64.ActiveCfg = Release|ARM64
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}.Release|ARM64.Build.0 = Release|ARM64
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}.Release|x64.ActiveCfg = Release|x64
{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}.Release|x64.Build.0 = Release|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|ARM64.ActiveCfg = Debug|ARM64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|ARM64.Build.0 = Debug|ARM64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.ActiveCfg = Debug|x64
@@ -2996,14 +2977,6 @@ Global
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|ARM64.Build.0 = Release|ARM64
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.ActiveCfg = Release|x64
{E816D7B4-4688-4ECB-97CC-3D8E798F3833}.Release|x64.Build.0 = Release|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.ActiveCfg = Debug|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|ARM64.Build.0 = Debug|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.ActiveCfg = Debug|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Debug|x64.Build.0 = Debug|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.ActiveCfg = Release|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|ARM64.Build.0 = Release|ARM64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.ActiveCfg = Release|x64
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5}.Release|x64.Build.0 = Release|x64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Build.0 = Debug|ARM64
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F}.Debug|ARM64.Deploy.0 = Debug|ARM64
@@ -3024,14 +2997,6 @@ Global
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA}.Release|ARM64.Build.0 = Release|ARM64
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA}.Release|x64.ActiveCfg = Release|x64
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA}.Release|x64.Build.0 = Release|x64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Debug|ARM64.ActiveCfg = Debug|ARM64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Debug|ARM64.Build.0 = Debug|ARM64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Debug|x64.ActiveCfg = Debug|x64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Debug|x64.Build.0 = Debug|x64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Release|ARM64.ActiveCfg = Release|ARM64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Release|ARM64.Build.0 = Release|ARM64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Release|x64.ActiveCfg = Release|x64
{45354F4F-1414-45CE-B600-51CD1209FD19}.Release|x64.Build.0 = Release|x64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Debug|ARM64.Build.0 = Debug|ARM64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Debug|x64.ActiveCfg = Debug|x64
@@ -3040,22 +3005,6 @@ Global
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|ARM64.Build.0 = Release|ARM64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|x64.ActiveCfg = Release|x64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|x64.Build.0 = Release|x64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Debug|ARM64.Build.0 = Debug|ARM64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Debug|x64.ActiveCfg = Debug|x64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Debug|x64.Build.0 = Debug|x64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Release|ARM64.ActiveCfg = Release|ARM64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Release|ARM64.Build.0 = Release|ARM64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Release|x64.ActiveCfg = Release|x64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Release|x64.Build.0 = Release|x64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Debug|ARM64.Build.0 = Debug|ARM64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Debug|x64.ActiveCfg = Debug|x64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Debug|x64.Build.0 = Debug|x64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Release|ARM64.ActiveCfg = Release|ARM64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Release|ARM64.Build.0 = Release|ARM64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Release|x64.ActiveCfg = Release|x64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -3381,14 +3330,10 @@ Global
{E816D7B3-4688-4ECB-97CC-3D8E798F3832} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7B2-4688-4ECB-97CC-3D8E798F3831} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7B4-4688-4ECB-97CC-3D8E798F3833} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{48A1DB8C-5DF8-4FB3-9E14-2B67F3F2D8B5} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{3DCCD936-D085-4869-A1DE-CA6A64152C94} = {5B201255-53C8-490B-A34F-01F05D48A477}
{F5333ED7-06D8-4AB3-953A-36D63F08CB6F} = {3DCCD936-D085-4869-A1DE-CA6A64152C94}
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{45354F4F-1414-45CE-B600-51CD1209FD19} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{2B3FB837-23DE-629F-82C6-42304E7083C9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{DB34808A-FF91-D06E-A426-AFB5A8BD583B} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

319
README.md
View File

@@ -7,9 +7,7 @@
<h1 align="center">
<span>Microsoft PowerToys</span>
</h1>
<p align="center">
<span align="center">Microsoft PowerToys is a collection of utilities that help you customize Windows and streamline everyday tasks.</span>
</p>
<h3 align="center">
<a href="#-installation">Installation</a>
<span> · </span>
@@ -20,10 +18,8 @@
<a href="#-whats-new">Release notes</a>
</h3>
<br/><br/>
## 🔨 Utilities
PowerToys includes over 25 utilities to help you customize and optimize your Windows experience:
Microsoft PowerToys is a collection of utilities that help you customize Windows and streamline everyday tasks.
<br/><br/>
| | | |
|---|---|---|
@@ -31,45 +27,50 @@ PowerToys includes over 25 utilities to help you customize and optimize your Win
| [<img src="doc/images/icons/Color%20Picker.png" alt="Color Picker icon" height="16"> Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [<img src="doc/images/icons/Command%20Not%20Found.png" alt="Command Not Found icon" height="16"> Command Not Found](https://aka.ms/PowerToysOverview_CmdNotFound) | [<img src="doc/images/icons/Command Palette.png" alt="Command Palette icon" height="16"> Command Palette](https://aka.ms/PowerToysOverview_CmdPal) |
| [<img src="doc/images/icons/Crop%20And%20Lock.png" alt="Crop and Lock icon" height="16"> Crop And Lock](https://aka.ms/PowerToysOverview_CropAndLock) | [<img src="doc/images/icons/Environment%20Manager.png" alt="Environment Variables icon" height="16"> Environment Variables](https://aka.ms/PowerToysOverview_EnvironmentVariables) | [<img src="doc/images/icons/FancyZones.png" alt="FancyZones icon" height="16"> FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
| [<img src="doc/images/icons/File%20Explorer%20Preview.png" alt="File Explorer Add-ons icon" height="16"> File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [<img src="doc/images/icons/File%20Locksmith.png" alt="File Locksmith icon" height="16"> File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) | [<img src="doc/images/icons/Host%20File%20Editor.png" alt="Hosts File Editor icon" height="16"> Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) |
| [<img src="doc/images/icons/Image%20Resizer.png" alt="Image Resizer icon" height="16"> Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [<img src="doc/images/icons/Keyboard%20Manager.png" alt="Keyboard Manager icon" height="16"> Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [<img src="doc/images/icons/Light Switch.png" alt="Light Switch icon" height="16"> Light Switch](https://aka.ms/PowerToysOverview_LightSwitch) |
| [<img src="doc/images/icons/Find My Mouse.png" alt="Mouse Utilities icon" height="16"> Mouse Utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [<img src="doc/images/icons/MouseWithoutBorders.png" alt="Mouse Without Borders icon" height="16"> Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [<img src="doc/images/icons/NewPlus.png" alt="New+ icon" height="16"> New+](https://aka.ms/PowerToysOverview_NewPlus) |
| [<img src="doc/images/icons/Peek.png" alt="Peek icon" height="16"> Peek](https://aka.ms/PowerToysOverview_Peek) | [<img src="doc/images/icons/PowerRename.png" alt="PowerRename icon" height="16"> PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [<img src="doc/images/icons/PowerToys%20Run.png" alt="PowerToys Run icon" height="16"> PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) |
| [<img src="doc/images/icons/PowerAccent.png" alt="Quick Accent icon" height="16"> Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | [<img src="doc/images/icons/Registry%20Preview.png" alt="Registry Preview icon" height="16"> Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [<img src="doc/images/icons/MeasureTool.png" alt="Screen Ruler icon" height="16"> Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) |
| [<img src="doc/images/icons/Shortcut%20Guide.png" alt="Shortcut Guide icon" height="16"> Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [<img src="doc/images/icons/PowerOCR.png" alt="Text Extractor icon" height="16"> Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [<img src="doc/images/icons/Workspaces.png" alt="Workspaces icon" height="16"> Workspaces](https://aka.ms/PowerToysOverview_Workspaces) |
| [<img src="doc/images/icons/ZoomIt.png" alt="ZoomIt icon" height="16"> ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) | | |
| [<img src="doc/images/icons/Image%20Resizer.png" alt="Image Resizer icon" height="16"> Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [<img src="doc/images/icons/Keyboard%20Manager.png" alt="Keyboard Manager icon" height="16"> Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) | [<img src="doc/images/icons/Find My Mouse.png" alt="Mouse Utilities icon" height="16"> Mouse Utilities](https://aka.ms/PowerToysOverview_MouseUtilities) |
| [<img src="doc/images/icons/MouseWithoutBorders.png" alt="Mouse Without Borders icon" height="16"> Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [<img src="doc/images/icons/NewPlus.png" alt="New+ icon" height="16"> New+](https://aka.ms/PowerToysOverview_NewPlus) | [<img src="doc/images/icons/Peek.png" alt="Peek icon" height="16"> Peek](https://aka.ms/PowerToysOverview_Peek) |
| [<img src="doc/images/icons/PowerRename.png" alt="PowerRename icon" height="16"> PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [<img src="doc/images/icons/PowerToys%20Run.png" alt="PowerToys Run icon" height="16"> PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [<img src="doc/images/icons/PowerAccent.png" alt="Quick Accent icon" height="16"> Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) |
| [<img src="doc/images/icons/Registry%20Preview.png" alt="Registry Preview icon" height="16"> Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [<img src="doc/images/icons/MeasureTool.png" alt="Screen Ruler icon" height="16"> Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [<img src="doc/images/icons/Shortcut%20Guide.png" alt="Shortcut Guide icon" height="16"> Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
| [<img src="doc/images/icons/PowerOCR.png" alt="Text Extractor icon" height="16"> Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [<img src="doc/images/icons/Workspaces.png" alt="Workspaces icon" height="16"> Workspaces](https://aka.ms/PowerToysOverview_Workspaces) | [<img src="doc/images/icons/ZoomIt.png" alt="ZoomIt icon" height="16"> ZoomIt](https://aka.ms/PowerToysOverview_ZoomIt) |
## 📋 Installation
For detailed installation instructions and system requirements, visit the [installation docs](https://learn.microsoft.com/windows/powertoys/install).
For detailed installation instructions, visit the [installation docs](https://learn.microsoft.com/windows/powertoys/install).
Before you begin, make sure your device meets the system requirements:
> [!NOTE]
> - Windows 11 or Windows 10 version 2004 (20H1 / build 19041) or newer
> - 64-bit processor: x64 or ARM64
> - Latest stable version of [Microsoft Edge WebView2 Runtime](https://go.microsoft.com/fwlink/p/?LinkId=2124703) is installed via the bootstrapper during setup
Choose one of the installation methods below:
<details>
<summary>Download .exe from GitHub</summary>
But to get started quickly, choose one of the installation methods below:
<br/><br/>
<details open>
<summary><strong>Download .exe from GitHub</strong></summary>
<br/>
Go to the [PowerToys GitHub releases][github-release-link], click Assets to reveal the downloads, and choose the installer that matches your architecture and install scope. For most devices, that's the x64 per-user installer.
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.97%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.96%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysUserSetup-0.96.1-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysUserSetup-0.96.1-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysSetup-0.96.1-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysSetup-0.96.1-arm64.exe
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.95%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.94%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysUserSetup-0.94.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysUserSetup-0.94.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysSetup-0.94.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysSetup-0.94.0-arm64.exe
| Description | Filename |
|----------------|----------|
| Per user - x64 | [PowerToysUserSetup-0.96.1-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.96.1-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.96.1-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.96.1-arm64.exe][ptMachineArm64] |
| Per user - x64 | [PowerToysUserSetup-0.94.0-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.94.0-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.94.0-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.94.0-arm64.exe][ptMachineArm64] |
</details>
<details>
<summary><strong>Microsoft Store</strong></summary>
<br/>
<summary>Microsoft Store</summary>
You can easily install PowerToys from the Microsoft Store:
<p>
<a style="text-decoration:none" href="https://aka.ms/getPowertoys">
@@ -80,9 +81,10 @@ You can easily install PowerToys from the Microsoft Store:
</p>
</details>
<details>
<summary><strong>WinGet</strong></summary>
<br/>
<summary>WinGet</summary>
Download PowerToys from [WinGet][winget-link]. Updating PowerToys via winget will respect the current PowerToys installation scope. To install PowerToys, run the following command from the command line / PowerShell:
*User scope installer [default]*
@@ -97,160 +99,181 @@ winget install --scope machine Microsoft.PowerToys -s winget
</details>
<details>
<summary><strong>Other methods</strong></summary>
<br/>
<summary>Other methods</summary>
There are [community driven install methods](./doc/unofficialInstallMethods.md) such as Chocolatey and Scoop. If these are your preferred install solutions, you can find the install instructions there.
</details>
## ✨ What's new
**Version 0.96 (November 2025)**
**Version 0.94 (September 2025)**
For an in-depth look at the latest changes, visit the [Windows Command Line blog](https://aka.ms/powertoys-releaseblog).
**✨ Highlights**
- Advanced Paste now supports multiple online and on-device AI model providers: Azure OpenAI, OpenAI, Google Gemini, Mistral, Foundry Local and Ollama.
- Command Palette received extensive improvements including file search filters, better clipboard history metadata, context-menu styling, and dozens of bug fixes and enhancements.
- PowerRename can now extract and use photo metadata (EXIF, XMP) in renaming patterns like `%Camera`, `%Lens`, and `%ExposureTime`.
### Advanced Paste
- Advanced Paste now lets you connect to multiple AI providers instead of being limited to a single OpenAI provider. See [Advanced Paste documentation](https://learn.microsoft.com/windows/powertoys/advanced-paste) for usage.
- PowerToys Settings added a Settings search with fuzzy matching, suggestions, a results page, and UX polish to make finding options faster.
- A comprehensive hotkey conflict detection system was introduced in Settings to surface and help resolve conflicting shortcuts. Note that the default hotkey settings (Win+Ctrl+Shift+T, Win+Ctrl+V, Win+Ctrl+T, Win+Shift+T) may overlap with existing Windows system shortcuts. This is expected. You can resolve the conflict by assigning different hotkeys.
- Mouse Utilities added a “Gliding cursor” accessibility feature to Mouse Pointer Crosshairs for singlebutton cursor movement and clicking. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
- The installer was upgraded to WiX 5 after WiX 3 reached end-of-life; this move improved installer security, reliability, and community support.
- Tons of bug fixes and improvements for Command Palette, including visual updates and new support for filters on ListPages (handy for extension developers).
- Hosts Editor now has a “No leading spaces” option so active host entries can start at column 0 even if others are disabled. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
- Context menu registration was moved from the installer to runtime to avoid loading disabled modules (runtime registrations).
- Quick Accent now supports Maltese, and frequently used accents appear first (and are remembered across sessions). Thanks [@rovercoder](https://github.com/rovercoder)! [@davidegiacometti](https://github.com/davidegiacometti)!
### Awake
- The Awake countdown timer now stays accurate over long periods. Thanks [@daverayment](https://github.com/daverayment)!
- Fixed Awake context menu positioning. The fix removed the conversion of the mouse cursor from screen to client-window coordinates, instead using the raw screen coordinates returned by GetCursorPos; the context menu now appears at the correct screen position. Thanks [@lzandman](https://github.com/lzandman)!
### Always On Top
- Fixed the border hover cursor so it shows the arrow instead of the wait cursor. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
### Command Palette
- The search field in context menus now matches the look of the Command Palette, with a smoke backdrop and improved padding.
- Fallback items such as math calculations or the Run command now appear in results more quickly. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Ensured the command bar updates correctly after navigating to another page and commands are displayed correctly. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- The Command Palette settings page has been reorganized. Activation-key options are grouped under an expander and extension settings are framed for improved readability.
- When you modify a command, its alias, hotkey, and tags now update in the top-level list, keeping the displayed information in sync. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Press `Ctrl + ,` to open Command Palette settings from anywhere. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- You can use `Page Up` and `Page Down` to navigate the list while focus is in the search box. Thanks [@samrueby](https://github.com/samrueby)!
- Fixed an issue where the search box could disappear when navigating pages. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Ensured search text is selected when *Go home when activated* and *Highlight search on activate* are both enabled. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Fixed an issue where Command Palette window occasionally appeared on the taskbar under certain Windows settings. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Ensured that labels and icons of list items and menu items update when they change. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Fixed visibility of list filters when navigating to a content page. Thanks [@DevLGuilherme](https://github.com/DevLGuilherme)!
- Added search to the extension list and a link to extensions on the Microsoft Store. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Added options to open the Command Palette window at its last position or re-center it.
- The Command Palette now remembers its window size after restarting.
- Added a global error handler that logs fatal errors and provides feedback when unexpected failures force Command Palette to close. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Fixed forms and extension settings not showing on some machines due to a missing VC++ runtime.
- Restored ranking of fallback commands for built-in extensions (Sleep, Shutdown, Windows settings, Web search, etc.). Thanks [@jiripolasek](https://github.com/jiripolasek).
- Improved and unified labels and texts across the application!
- Maintainance: Resolved numerous build warnings in Command Palette projects; no user-visible impact. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Maintainance: Fixed a logging issue so exception messages are properly recorded instead of placeholder text, improving troubleshooting. Thanks [@jiripolasek](https://github.com/jiripolasek)!
### Command Palette Extensions
- Bookmarks: Added hints about bookmark placeholders to the Add/Edit Bookmark form. — Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Bookmarks: Improved migration of bookmarks from older versions and fixed an issue where aliases or keyboard shortcuts could be lost after restart. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Clipboard history: Items shown in Command Palettes clipboard history now include helpful metadata. For example, image items show dimensions, text files show names and sizes, web links include page titles, and text entries display word counts. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- File search: Added filter buttons to show *all items*, *files only*, or *folders only*. Selecting a filter adds `kind:folders` or `kind:not folders` to narrow results.
- System commands: Replaced the `:red_circle:` placeholder with an actual red-circle emoji so the correct icon appears in the UI. Thanks [@samrueby](https://github.com/samrueby)!
- WinGet: Search performance feels more responsive because typed input is now processed via a task queue rather than complex cancellation tokens!
- Window Walker: UWP apps no longer show a "not responding" label when suspended. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Window Walker: Now displays the actual icon of each window rather than using the process icon, improving recognition of PWAs and Python GUIs. Thanks [@Lee-WonJun](https://github.com/Lee-WonJun)!
- Windows Terminal profiles: Fixed a rare crash in the Windows Terminal extension when the `LOCALAPPDATA` environment variable was missing. The path is now retrieved via a reliable API. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Applied single-click activation only to pointer input; keyboard always activates immediately. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Let context menus open at the cursor by removing window-bound constraints. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Made error messages clearer with timestamps, HRESULTs, and full details for easier diagnosis. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Prevented crashes and improved robustness when updating providers without commands. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Ensured the Settings window reliably comes to the front when opened. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Replaced the Clipboard History icon with a colorful Fluent icon. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Hardened ContentIcon to avoid duplicate parenting and improve diagnostics. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Standardized null checks using C# pattern matching for safer behavior.
- Improved accessibility by focusing the activation shortcut dialog and making text reachable. Thanks [@chatasweetie](https://github.com/chatasweetie)!
- Moved the extension SDK to a stable Windows SDK and cleaned up message namespaces.
- Added path shortcuts: ~ to home, and / or \\ to system root, plus UNC support. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Fixed a race in cancellation handling to avoid InvalidOperationException. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Aligned separator styling with WinUI 3 for consistent visuals. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Added ARM64 PDBs to the Extensions SDK NuGet for better debugging.
- Added single-select filters to DynamicListPage and updated Windows Services sample.
- Updated main page placeholder text to better describe what can be searched. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Removed explicit WinAppSDK/WebView2 dependencies from toolkit and API. Thanks [@rluengen](https://github.com/rluengen)!
- Added a local keyboard hook to handle the GoBack key reliably. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Propagated alias changes safely and resolved conflicts across view models.
- Allowed providers to override Dispose with a virtual method.
- Fixed memory leaks by cleaning up removed or cancelled list items.
- Sorted DateTime extension results by relevance for better usability.
- Reduced search text "jiggling" by avoiding redundant change notifications.
- Centralized automation notifications in a UIHelper for better accessibility. Thanks [@chatasweetie](https://github.com/chatasweetie)!
- Preserved Adaptive Card action types during trimming via DynamicDependency.
- Added an acrylic backdrop and refined styling to the context menu. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Prevented disposed pages and Settings windows from handling stale messages. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Made the extension API easier to evolve without breaking clients.
- Added "evil" sample pages to help reproduce tricky bugs.
- Fixed WinGet trim-safety issues by replacing LINQ with manual iteration.
- Cancelled stale list fetches to avoid older results overwriting newer ones in CmdPal.
### Find My Mouse
- Activating Find My Mouse no longer makes the cursor change to the busy (hourglass) icon or steals focus from your active application.
### Command Palette extensions
- Improved empty states and ranking logic for multiple extensions. Thanks [@htcfreek](https://github.com/htcfreek)!
- Added app icons to the All Apps "Run" context command when available.
- Restored missing builtin icons by standardizing extension dependencies.
- Unblocked local deployment by adding WinAppSDK to two sample extensions.
### Hosts File Editor
- Added customizable backup settings allowing users to configure backup frequency, location, and auto-deletion policies. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Added a "No leading spaces" option so active hosts entries can start at column 0 even when others are disabled. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
### Image Resizer
- Fixed settings consistency during batch resize operations by capturing settings once before processing. Thanks [@daverayment](https://github.com/daverayment)!
### Light Switch
- Introduced new UI to allow users to manually enter their latitude and longitude in Sunrise to Sunset mode.
- Refactored service with cleaner state management for stability.
- Removed logs from every tick, only logging key events to largely reduce log size.
- Fixed Image Resizer localization by installing satellite resources under the WinUI 3 apps culture path.
### Mouse Pointer Crosshairs
- Enabled switching between Mouse Pointer Crosshairs and Gliding Cursor modes. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
### Mouse Utilities
- Introduced "Gliding cursor" to control the pointer and click with a single hotkey for better accessibility. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
### Mouse Without Borders
- Added horizontal scrolling support. Thanks [@MasonBergstrom](https://github.com/MasonBergstrom)!
- Blocked Easy Mouse from switching machines during fullscreen apps, with an allow-list for exceptions. Thanks [@dot-tb](https://github.com/dot-tb)!
### Peek
- Fixed media files remaining locked after preview window closes. Thanks [@daverayment](https://github.com/daverayment)!
- Added a command-line interface for file previewing. See the [Peek documentation](https://learn.microsoft.com/windows/powertoys/peek) for usage. Thanks [@prochan2](https://github.com/prochan2)!
- Added Visual Studio shared project file types to XML preview and fixed bgcode handler registration. Thanks [@rezanid](https://github.com/rezanid)!
- Fixes bgcode preview handler registration and events for reliable previews. Thanks [@pedrolamas](https://github.com/pedrolamas)!
### PowerRename
- PowerRename no longer crashes due to a missing resources file.
- Added photo metadata extraction support using EXIF and XMP for pattern-based renaming with camera info, GPS coordinates, and date taken. See [PowerRename Documentation](https://learn.microsoft.com/en-us/windows/powertoys/powerrename).
### PowerToys Run
- Added retry logic with exponential backoff to handle DWM composition errors during theme changes. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Updated OneNote icons to reflect new Microsoft 365 design. Thanks [@trevorNgo](https://github.com/trevorNgo)!
- Changed the Explorer accelerator key to PowErRename to avoid clashing with the New menu. Thanks [@aaron-ni](https://github.com/aaron-ni)!
### Quick Accent
- Added diameter symbol (⌀) for Shift+O in Special Characters mode, thanks to [@anselumjuju](https://github.com/anselumjuju)!
### Quick Accent
### Zoomit
- Smoothed out zoom-animation in ZoomIt by coalescing mouse-move and timer events, thanks to [@foxmsft](https://github.com/foxmsft)!
- Enabled GIF support for ZoomIt, thanks to [@MarioHewardt](https://github.com/MarioHewardt)!
- Fixed spelling mistakes, and refactored some literal strings to string constants, thanks to [@lzandman](https://github.com/lzandman)!
- Fixed inaccurate "actual size" screenshots in ZoomIt and resolves a GDI handle leak, improving capture fidelity and long-session stability. thanks to [@daverayment](https://github.com/daverayment)!
- Remembered character usage across sessions so frequently used accents appear first. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Added Maltese language support with specific characters and the Euro symbol. Thanks [@rovercoder](https://github.com/rovercoder)!
- Reduced GPU usage issues by making the window Topmost only when the picker is visible. Thanks [@daverayment](https://github.com/daverayment)!
### Settings
- Fixed title bar overlapping issue at smaller window sizes.
- Refined shortcut control visual design with improved consistency and spacing.
- Added dashboard utilities sorting by name or status.
- Made update notification InfoBar in flyout clickable for direct navigation to update page.
- Expanded installation instructions by default in README.
- Improved accessibility for shortcut conflict button with static resource-based automation properties.
- Added ScrollViewer to Command Palette page in PowerToys Settings. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Fixed module list glitches and Sort Status checkmark issue. Thanks [@daverayment](https://github.com/daverayment)!
- Added telemetry to track usage of the new shortcut conflict detection workflow.
- Moved the shutdown action from the title bar to a footer menu item with confirmation. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Implemented comprehensive hotkey conflict detection with a dedicated resolution dialog.
- Added branded visuals for Office and Copilot keys in the KeyVisual control.
- Introduced Settings search with fuzzy matching and navigation to specific controls.
- Corrected Spanish localization so product names like Awake remain in English across Settings and OOBE.
- Simplified the Advanced Paste description in Settings for quicker reading and consistent capitalization. Thanks [@OldUser101](https://github.com/OldUser101)!
- Localized conflict messages in the conflict window and dialog.
### Installer
- Upgraded the installer to WiX 5 with silent "Files in Use" handling for smoother winget installs.
- Switched Win10 context menu modules to runtime registration and added cleanup on uninstall to avoid stale entries.
### Documentation
- Adds docs for building the installer locally and testing winget installs.
- Fixed a broken style guide link in developer documentation. Thanks [@denizmaral](https://github.com/denizmaral)!
### Development
- Fixed accessibility by associating controls with labels for screen readers.
- Added accessible name to Shortcut Conflicts button for screen readers.
- Excluded TitleBars from tab navigation across multiple utilities. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Migrated build infrastructure from Windows Server 2019 to Server 2022 with improved failure logging and predictable NuGet package paths.
- Configured build agents to use larger P: drive for release builds to address disk space constraints.
- Enhanced DSC v3 support by organizing resource manifests in a dedicated subfolder with PATH configuration.
- Reduced installer bundle size by 6-7MB through centralized Hybrid CRT configuration across all C++ projects.
- Updated .NET packages to version 9.0.10 for security fixes. Thanks [@snickler](https://github.com/snickler)!
- Fixed spell check dictionary entries for consistency.
- Restored accidentally deleted NuGet configuration file for Command Palette extensions.
- Fixed package identity build by updating AppxManifest entry points to use PowerShell Core.
- Optimized CI pipeline by replacing file copy operations with hard links and moves, reducing build time and disk usage by 10-15GB.
- Updated Copilot guidance and PR prompt workflow.
- Included high-volume bugs in issue template header. Thanks [@daverayment](https://github.com/daverayment)!
- Fixed incorrect HRESULT logging for inner exceptions. Thanks [@jiripolasek](https://github.com/jiripolasek)!
- Introduced shared sparse package identity for PowerToys Win32 components to enable access to Windows platform APIs.
- Consolidated installer builds to produce both machine and user installers simultaneously, reducing build time and complexity.
- Migrated exclusively to WiX v5 installer infrastructure, removing legacy WiX v3 support.
- Temporarily removed PowerToys installer path from PATH environment variable to prevent application crashes.
- Added complete OCR UI test coverage with automated tests for activation, settings, language selection, and text extraction.
- Fixed test input for drive path normalization in bookmark resolver unit tests.
- Fixed Peek UI tests by restoring Ctrl+Space activation shortcut for test scenarios.
- Hided apps in PowerToys.SpareApps package from Start Menu. Thanks [@jiripolasek](https://github.com/jiripolasek)!
## 🛣️ Roadmap
We are planning some nice new features and improvements for the next releases a revamped Keyboard Manager UI, custom endpoint and local model support for Advanced Paste, Command Palette improvements and a brand-new Shortcut Guide experience! Stay tuned for [v0.96][github-next-release-work]!
- Excluded test and coverage DLLs from BinSkim scans to cut false positives and speed up security analysis.
- Simplified NOTICE maintenance by removing version numbers and filtering out Microsoft/System packages.
- Improved NuGet dependency validation to prevent package downgrades and catch issues during restore.
- Updated UTF.Unknown to a modern version to improve compatibility without breaking changes. Thanks [@304NotModified](https://github.com/304NotModified)!
- Refreshed package catalog in CI before installing dependencies to prevent Linux workflow failures.
- Refactored CmdPal tests with dependency injection and added coverage for queries and settings.
- Added unit tests to verify Close on Enter swaps Copy/Save as expected. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
- Added accessibility IDs to CmdPal UI for stable UI tests.
- Rewrote system command tests with a new test base and cleaner patterns.
- Added unit tests for WebSearch and Shell extensions with mockable settings.
- Added unit tests and abstractions for Apps and Bookmarks extensions.
- Cleans up AI-generated tests; adds meaningful query tests across extensions.
- Removed the obsolete debug dialog from Settings for a smoother developer loop.
## 🛣️ Roadmap
For [v0.95][github-next-release-work], we'll work on the items below:
- Continued Command Palette polish
- Working on Shortcut Guide v2 (Thanks [@noraa-junker](https://github.com/noraa-junker)!)
- Upgrading Keyboard Manager's editor UI
- UI tweaking utility with day/night theme switcher
- DSC v3 support for top utilities
- New UI automation tests
- Stability, bug fixes
## ❤️ PowerToys Community
## ❤️ PowerToys Community
The PowerToys team is extremely grateful to have the [support of an amazing active community][community-link]. The work you do is incredibly important. PowerToys wouldn't be nearly what it is today without your help filing bugs, updating documentation, guiding the design, or writing features. We want to say thank you and take time to recognize your work. Your contributions and feedback improve PowerToys month after month!
## Contributing
This project welcomes contributions of all types. Besides coding features / bug fixes, other ways to assist include spec writing, design, documentation, and finding bugs. We are excited to work with the power user community to build a set of tools for helping you get the most out of Windows. We ask that **before you start work on a feature that you would like to contribute**, please read our [Contributor's Guide](CONTRIBUTING.md). We would be happy to work with you to figure out the best approach, provide guidance and mentorship throughout feature development, and help avoid any wasted or duplicate effort. Most contributions require you to agree to a [Contributor License Agreement (CLA)][oss-CLA] declaring that you grant us the rights to use your contribution and that you have permission to do so. For guidance on developing for PowerToys, please read the [developer docs](./doc/devdocs) for a detailed breakdown. This includes how to setup your computer to compile.
## Contributing
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct][oss-conduct-code].
This project welcomes contributions of all types. Besides coding features / bug fixes, other ways to assist include spec writing, design, documentation, and finding bugs. We are excited to work with the power user community to build a set of tools for helping you get the most out of Windows.
## Privacy Statement
The application logs basic diagnostic data (telemetry). For more privacy information and what we collect, see our [PowerToys Data and Privacy documentation](https://aka.ms/powertoys-data-and-privacy-documentation).
We ask that **before you start work on a feature that you would like to contribute**, please read our [Contributor's Guide](CONTRIBUTING.md). We would be happy to work with you to figure out the best approach, provide guidance and mentorship throughout feature development, and help avoid any wasted or duplicate effort.
[oss-CLA]: https://cla.opensource.microsoft.com
[oss-conduct-code]: CODE_OF_CONDUCT.md
[community-link]: COMMUNITY.md
[github-release-link]: https://aka.ms/installPowerToys
[microsoft-store-link]: https://aka.ms/getPowertoys
[winget-link]: https://github.com/microsoft/winget-cli#installing-the-client
Most contributions require you to agree to a [Contributor License Agreement (CLA)][oss-CLA] declaring that you grant us the rights to use your contribution and that you have permission to do so.
For guidance on developing for PowerToys, please read the [developer docs](./doc/devdocs) for a detailed breakdown. This includes how to setup your computer to compile.
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct][oss-conduct-code].
## Privacy Statement
The application logs basic diagnostic data (telemetry). For more privacy information and what we collect, see our [PowerToys Data and Privacy documentation](https://aka.ms/powertoys-data-and-privacy-documentation).
[oss-CLA]: https://cla.opensource.microsoft.com
[oss-conduct-code]: CODE_OF_CONDUCT.md
[community-link]: COMMUNITY.md
[github-release-link]: https://aka.ms/installPowerToys
[microsoft-store-link]: https://aka.ms/getPowertoys
[winget-link]: https://github.com/microsoft/winget-cli#installing-the-client
[roadmap]: https://github.com/microsoft/PowerToys/wiki/Roadmap
[privacy-link]: http://go.microsoft.com/fwlink/?LinkId=521839
[loc-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=translation_issue.md&title=
[privacy-link]: http://go.microsoft.com/fwlink/?LinkId=521839
[loc-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=translation_issue.md&title=
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs

1
deps/cziplib vendored Submodule

Submodule deps/cziplib added at 81314fff0a

View File

@@ -33,12 +33,9 @@ The **Light Switch** module lets users automatically transition between light an
> **Note:** Using the shortcut overrides the current schedule until the next transition event.
* **LightSwitchService.cpp**
is the heart beat of the module. Controls ticking every minute and depending on user actions (manual override, settings changing, etc) triggers the state manager to perform the corresponding operation.
* **LightSwitchStateManager.cpp**
handles updating the state based on the signals sent by LightSwitchService.
* **LightSwitchService**
Reads settings and applies theming. Runs a check every minute to ensure the state is correct.
* **SettingsXAML/LightSwitch**
Provides the settings UI for configuring schedules, syncing location, and customizing shortcuts.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,87 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True)]
[string]$dscWxsFile,
[Parameter(Mandatory = $True)]
[string]$Platform,
[Parameter(Mandatory = $True)]
[string]$Configuration
)
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$buildOutputDir = Join-Path $scriptDir "..\..\$Platform\$Configuration"
if (-not (Test-Path $buildOutputDir)) {
Write-Error "Build output directory not found: '$buildOutputDir'"
exit 1
}
$dscFiles = Get-ChildItem -Path $buildOutputDir -Filter "microsoft.powertoys.*.settings.dsc.resource.json" -File
if (-not $dscFiles) {
Write-Warning "No DSC manifest files found in '$buildOutputDir'"
$wxsContent = @"
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
exit 0
}
Write-Host "Found $($dscFiles.Count) DSC manifest file(s)"
$wxsContent = @"
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder">
"@
$componentRefs = @()
foreach ($file in $dscFiles) {
$componentId = "DscResource_" + ($file.BaseName -replace '[^A-Za-z0-9_]', '_')
$fileId = $componentId + "_File"
$guid = [System.Guid]::NewGuid().ToString().ToUpper()
$componentRefs += $componentId
$wxsContent += @"
<Component Id="$componentId" Guid="{$guid}">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$componentId" Value="" KeyPath="yes"/>
</RegistryKey>
<File Id="$fileId" Source="`$(var.BinDir)$($file.Name)" Vital="no"/>
</Component>
"@
}
$wxsContent += @"
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
"@
foreach ($componentId in $componentRefs) {
$wxsContent += @"
<ComponentRef Id="$componentId"/>
"@
}
$wxsContent += @"
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
Write-Host "Generated DSC resources WiX fragment: '$dscWxsFile'"

View File

@@ -4,7 +4,6 @@
#include <ProjectTelemetry.h>
#include <spdlog/sinks/base_sink.h>
#include <filesystem>
#include <string_view>
#include "../../src/common/logger/logger.h"
#include "../../src/common/utils/gpo.h"
@@ -595,216 +594,6 @@ LExit:
return WcaFinalize(er);
}
UINT __stdcall InstallPackageIdentityMSIXCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
LPWSTR customActionData = nullptr;
std::wstring installFolderPath;
std::wstring installScope;
std::wstring msixPath;
std::wstring data;
size_t delimiterPos;
bool isMachineLevel = false;
hr = WcaInitialize(hInstall, "InstallPackageIdentityMSIXCA");
ExitOnFailure(hr, "Failed to initialize");
hr = WcaGetProperty(L"CustomActionData", &customActionData);
ExitOnFailure(hr, "Failed to get CustomActionData property");
// Parse CustomActionData: "[INSTALLFOLDER];[InstallScope]"
data = customActionData;
delimiterPos = data.find(L';');
installFolderPath = data.substr(0, delimiterPos);
installScope = data.substr(delimiterPos + 1);
// Check if this is a machine-level installation
if (installScope == L"perMachine")
{
isMachineLevel = true;
}
Logger::info(L"Installing PackageIdentity MSIX - perUser: {}", !isMachineLevel);
// Construct path to PackageIdentity MSIX
msixPath = installFolderPath;
msixPath += L"PowerToysSparse.msix";
if (std::filesystem::exists(msixPath))
{
using namespace winrt::Windows::Management::Deployment;
using namespace winrt::Windows::Foundation;
try
{
std::wstring externalLocation = installFolderPath; // External content location (PowerToys install folder)
Uri externalUri{ externalLocation }; // External location URI for sparse package content
Uri packageUri{ msixPath }; // The MSIX file URI
PackageManager packageManager;
if (isMachineLevel)
{
// Machine-level installation
StagePackageOptions stageOptions;
stageOptions.ExternalLocationUri(externalUri);
auto stageResult = packageManager.StagePackageByUriAsync(packageUri, stageOptions).get();
uint32_t stageErrorCode = static_cast<uint32_t>(stageResult.ExtendedErrorCode());
if (stageErrorCode == 0)
{
std::wstring packageFamilyName = L"Microsoft.PowerToys.SparseApp_8wekyb3d8bbwe";
try
{
auto provisionResult = packageManager.ProvisionPackageForAllUsersAsync(packageFamilyName).get();
uint32_t provisionErrorCode = static_cast<uint32_t>(provisionResult.ExtendedErrorCode());
if (provisionErrorCode != 0)
{
Logger::error(L"Machine-level provisioning failed: 0x{:08X}", provisionErrorCode);
}
}
catch (const winrt::hresult_error& ex)
{
Logger::error(L"Provisioning exception: HRESULT 0x{:08X}", static_cast<uint32_t>(ex.code()));
}
}
else
{
Logger::error(L"Package staging failed: 0x{:08X}", stageErrorCode);
}
}
else
{
AddPackageOptions addOptions;
addOptions.ExternalLocationUri(externalUri);
auto addResult = packageManager.AddPackageByUriAsync(packageUri, addOptions).get();
if (!addResult.IsRegistered())
{
uint32_t errorCode = static_cast<uint32_t>(addResult.ExtendedErrorCode());
Logger::error(L"Per-user installation failed: 0x{:08X}", errorCode);
}
}
}
catch (const std::exception& ex)
{
Logger::error(L"PackageIdentity MSIX installation failed - Exception: {}",
winrt::to_hstring(ex.what()).c_str());
}
}
else
{
Logger::error(L"PackageIdentity MSIX not found: " + msixPath);
}
LExit:
ReleaseStr(customActionData);
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall UninstallPackageIdentityMSIXCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
using namespace winrt::Windows::Management::Deployment;
using namespace winrt::Windows::Foundation;
LPWSTR installScope = nullptr;
bool isMachineLevel = false;
PackageManager pm;
hr = WcaInitialize(hInstall, "UninstallPackageIdentityMSIXCA");
ExitOnFailure(hr, "Failed to initialize");
// Check if this was a machine-level installation
hr = WcaGetProperty(L"InstallScope", &installScope);
if (SUCCEEDED(hr) && installScope && wcscmp(installScope, L"perMachine") == 0)
{
isMachineLevel = true;
}
Logger::info(L"Uninstalling PackageIdentity MSIX - perUser: {}", !isMachineLevel);
try
{
std::wstring packageFamilyName = L"Microsoft.PowerToys.SparseApp_8wekyb3d8bbwe";
if (isMachineLevel)
{
// Machine-level uninstallation: deprovision + remove for all users
// First deprovision the package
try
{
auto deprovisionResult = pm.DeprovisionPackageForAllUsersAsync(packageFamilyName).get();
if (deprovisionResult.IsRegistered())
{
Logger::warn(L"Machine-level deprovisioning completed with warnings");
}
}
catch (const winrt::hresult_error& ex)
{
Logger::warn(L"Machine-level deprovisioning failed: HRESULT 0x{:08X}", static_cast<uint32_t>(ex.code()));
}
// Then remove packages for all users
auto packages = pm.FindPackagesForUserWithPackageTypes({}, packageFamilyName, PackageTypes::Main);
for (const auto& package : packages)
{
try
{
auto machineResult = pm.RemovePackageAsync(package.Id().FullName(), RemovalOptions::RemoveForAllUsers).get();
if (machineResult.IsRegistered())
{
uint32_t errorCode = static_cast<uint32_t>(machineResult.ExtendedErrorCode());
Logger::error(L"Machine-level removal failed: 0x{:08X} - {}", errorCode, machineResult.ErrorText());
}
}
catch (const winrt::hresult_error& ex)
{
Logger::error(L"Machine-level removal exception: HRESULT 0x{:08X}", static_cast<uint32_t>(ex.code()));
}
}
}
else
{
// Per-user uninstallation: standard removal
auto packages = pm.FindPackagesForUserWithPackageTypes({}, packageFamilyName, PackageTypes::Main);
for (const auto& package : packages)
{
auto userResult = pm.RemovePackageAsync(package.Id().FullName()).get();
if (userResult.IsRegistered())
{
uint32_t errorCode = static_cast<uint32_t>(userResult.ExtendedErrorCode());
Logger::error(L"Per-user removal failed: 0x{:08X} - {}", errorCode, userResult.ErrorText());
}
}
}
}
catch (const std::exception& ex)
{
std::string errorMsg = "Failed to uninstall PackageIdentity MSIX: " + std::string(ex.what());
Logger::error(errorMsg);
// Don't fail the entire uninstallation if PackageIdentity fails
Logger::warn(L"Continuing uninstallation despite PackageIdentity MSIX error");
}
LExit:
ReleaseStr(installScope);
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall RemoveWindowsServiceByName(std::wstring serviceName)
{
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
@@ -857,69 +646,14 @@ UINT __stdcall UnsetAdvancedPasteAPIKeyCA(MSIHANDLE hInstall)
try
{
winrt::Windows::Security::Credentials::PasswordVault vault;
winrt::Windows::Security::Credentials::PasswordCredential cred;
hr = WcaInitialize(hInstall, "UnsetAdvancedPasteAPIKey");
ExitOnFailure(hr, "Failed to initialize");
winrt::Windows::Security::Credentials::PasswordVault vault;
auto hasPrefix = [](std::wstring_view value, wchar_t const* prefix) {
std::wstring_view prefixView{ prefix };
return value.compare(0, prefixView.size(), prefixView) == 0;
};
const wchar_t* resourcePrefixes[] = {
L"https://platform.openai.com/api-keys",
L"https://azure.microsoft.com/products/ai-services/openai-service",
L"https://azure.microsoft.com/products/ai-services/ai-inference",
L"https://console.mistral.ai/account/api-keys",
L"https://ai.google.dev/",
};
const wchar_t* usernamePrefixes[] = {
L"PowerToys_AdvancedPaste_",
};
auto credentials = vault.RetrieveAll();
for (auto const& credential : credentials)
{
bool shouldRemove = false;
std::wstring resource{ credential.Resource() };
for (auto const prefix : resourcePrefixes)
{
if (hasPrefix(resource, prefix))
{
shouldRemove = true;
break;
}
}
if (!shouldRemove)
{
std::wstring username{ credential.UserName() };
for (auto const prefix : usernamePrefixes)
{
if (hasPrefix(username, prefix))
{
shouldRemove = true;
break;
}
}
}
if (!shouldRemove)
{
continue;
}
try
{
vault.Remove(credential);
}
catch (...)
{
}
}
cred = vault.Retrieve(L"https://platform.openai.com/api-keys", L"PowerToys_AdvancedPaste_OpenAIKey");
vault.Remove(cred);
}
catch (...)
{

View File

@@ -33,5 +33,3 @@ EXPORTS
CleanPowerRenameRuntimeRegistryCA
CleanNewPlusRuntimeRegistryCA
SetBundleInstallLocationCA
InstallPackageIdentityMSIXCA
UninstallPackageIdentityMSIXCA

View File

@@ -34,8 +34,13 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(Platform)\$(Configuration)\SetupShared\</OutDir>
<IntDir>$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\SetupShared\obj\</IntDir>
<OutDir Condition=" '$(PerUser)' != 'true' ">$(Platform)\$(Configuration)\MachineSetup\</OutDir>
<OutDir Condition=" '$(PerUser)' == 'true' ">$(Platform)\$(Configuration)\UserSetup\</OutDir>
<IntDir Condition=" '$(PerUser)' != 'true' ">$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\MachineSetup\obj\</IntDir>
<IntDir Condition=" '$(PerUser)' == 'true' ">$(SolutionDir)$(ProjectName)\$(Platform)\$(Configuration)\UserSetup\obj\</IntDir>
<!-- The CMD script below checks this value, and it is **CASE SENSITIVE** -->
<NormalizedPerUserValue>false</NormalizedPerUserValue>
<NormalizedPerUserValue Condition=" '$(PerUser)' == 'true' ">true</NormalizedPerUserValue>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<LinkIncremental>true</LinkIncremental>
@@ -54,7 +59,6 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\CmdPal.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\CmdPal.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\ColorPicker.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\ColorPicker.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Core.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Core.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\DscResources.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\DscResources.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\EnvironmentVariables.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\EnvironmentVariables.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\FileExplorerPreview.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\FileExplorerPreview.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\FileLocksmith.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\FileLocksmith.wxs.bk""""
@@ -76,7 +80,8 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinAppSDK.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\WinUI3Applications.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs"" ""$(ProjectDir)..\PowerToysSetupVNext\Workspaces.wxs.bk""""
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
if not "$(NormalizedPerUserValue)" == "true" call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform)
if "$(NormalizedPerUserValue)" == "true" call powershell.exe -NonInteractive -executionpolicy Unrestricted -File ..\PowerToysSetupVNext\generateAllFileComponents.ps1 -platform $(Platform) -installscopeperuser $(NormalizedPerUserValue)
</Command>
<Message>Backing up original files and populating .NET and WPF Runtime dependencies for WiX3 based installer</Message>
</PreBuildEvent>
@@ -176,4 +181,4 @@
<Error Condition="!Exists('..\packages\WixToolset.DUtil.5.0.2\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.DUtil.5.0.2\build\WixToolset.DUtil.props'))" />
<Error Condition="!Exists('..\packages\WixToolset.WcaUtil.5.0.2\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WixToolset.WcaUtil.5.0.2\build\WixToolset.WcaUtil.props'))" />
</Target>
</Project>
</Project>

View File

@@ -4,13 +4,6 @@
<Fragment>
<DirectoryRef Id="WinUI3AppsInstallFolder">
<Directory Id="CmdPalInstallFolder" Name="CmdPal">
<Directory Id="CmdPalDepsInstallFolder" Name="Dependencies">
<?if $(sys.BUILDARCH) = x64 ?>
<Directory Id="CmdPalDepsX64InstallFolder" Name="x64" />
<?else?>
<Directory Id="CmdPalDepsArm64InstallFolder" Name="arm64" />
<?endif?>
</Directory>
</Directory>
</DirectoryRef>
<DirectoryRef Id="CmdPalInstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test">
@@ -25,40 +18,14 @@
<?endif?>
</Component>
</DirectoryRef>
<?if $(sys.BUILDARCH) = x64 ?>
<DirectoryRef Id="CmdPalDepsX64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64">
<Component Id="Module_CmdPal_Deps" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes" />
</RegistryKey>
<File Id="Microsoft.VCLibs.x64.14.00.Desktop.appx" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx" />
</Component>
</DirectoryRef>
<?else?>
<DirectoryRef Id="CmdPalDepsArm64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64">
<Component Id="Module_CmdPal_Deps" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes" />
</RegistryKey>
<File Id="Microsoft.VCLibs.ARM64.14.00.Desktop.appx" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64\Microsoft.VCLibs.ARM64.14.00.Desktop.appx" />
</Component>
</DirectoryRef>
<?endif?>
<ComponentGroup Id="CmdPalComponentGroup">
<Component Id="RemoveCmdPalFolder" Guid="2DF90C08-CC75-4245-A14E-B82904636C53" Directory="INSTALLFOLDER">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveCmdPalFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveCmdPalInstallDirFolder" Directory="CmdPalInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveCmdPalDepsInstallDirFolder" Directory="CmdPalDepsInstallFolder" On="uninstall" />
<?if $(sys.BUILDARCH) = x64 ?>
<RemoveFolder Id="RemoveCmdPalDepsX64InstallDirFolder" Directory="CmdPalDepsX64InstallFolder" On="uninstall" />
<?else?>
<RemoveFolder Id="RemoveCmdPalDepsArm64InstallDirFolder" Directory="CmdPalDepsArm64InstallFolder" On="uninstall" />
<?endif?>
</Component>
<ComponentRef Id="Module_CmdPal" />
<ComponentRef Id="Module_CmdPal_Deps" />
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -9,25 +9,6 @@
<RegistryValue Type="string" Name="InstallScope" Value="$(var.InstallScope)" />
</RegistryKey>
</Component>
<?if $(var.PerUser) = "true" ?>
<Component Id="powertoys_env_path_user" Bitness="always64">
<!-- Anchor registry for component key path -->
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="powertoys_env_path_user" Value="" KeyPath="yes" />
</RegistryKey>
<!-- Append DSCModules folder to current user's PATH for DSC v3 usage -->
<Environment Id="AddPowerToysToUserPath" Name="PATH" Action="set" Part="last" System="no" Value="[DSCModulesReferenceFolder]" />
</Component>
<?else?>
<Component Id="powertoys_env_path_machine" Bitness="always64">
<!-- Anchor registry for component key path -->
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="powertoys_env_path_machine" Value="" KeyPath="yes" />
</RegistryKey>
<!-- Append DSCModules folder to machine PATH for DSC v3 usage -->
<Environment Id="AddPowerToysToMachinePath" Name="PATH" Action="set" Part="last" System="yes" Value="[DSCModulesReferenceFolder]" />
</Component>
<?endif?>
<Component Id="powertoys_toast_clsid" Bitness="always64">
<RemoveFolder Id="Remove_powertoys_toast_clsid" On="uninstall" />
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{DD5CACDA-7C2E-4997-A62A-04A597B58F76}">
@@ -63,6 +44,16 @@
</Component>
</DirectoryRef>
<DirectoryRef Id="DSCModulesReferenceFolder">
<Component Id="PowerToysDSCReference" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes" />
</RegistryKey>
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
</Component>
</DirectoryRef>
<?if $(var.PerUser) = "true" ?>
<!-- DSC module files for PerUser handled in InstallDSCModule custom action. -->
<?else?>
@@ -110,6 +101,7 @@
<RegistryValue Type="string" Name="RemoveCoreFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveBaseApplicationsAssetsFolder" Directory="BaseApplicationsAssetsFolder" On="uninstall" />
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall" />
<RemoveFolder Id="RemoveWinUI3AppsInstallFolder" Directory="WinUI3AppsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveWinUI3AppsAssetsFolder" Directory="WinUI3AppsAssetsFolder" On="uninstall" />
<RemoveFolder Id="RemoveINSTALLFOLDER" Directory="INSTALLFOLDER" On="uninstall" />
@@ -121,11 +113,7 @@
<ComponentRef Id="License_rtf" />
<ComponentRef Id="Notice_md" />
<ComponentRef Id="DesktopShortcut" />
<?if $(var.PerUser) = "true" ?>
<ComponentRef Id="powertoys_env_path_user" />
<?else?>
<ComponentRef Id="powertoys_env_path_machine" />
<?endif?>
<ComponentRef Id="PowerToysDSCReference" />
<?if $(var.PerUser) = "false" ?>
<ComponentRef Id="PowerToysDSC" />
<?endif?>

View File

@@ -1,33 +0,0 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include $(sys.CURRENTDIR)\Common.wxi?>
<?define DscJsonFiles=?>
<?define DscJsonFilesPath=$(var.BinDir)\DSCModules?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder" FileSource="$(var.DscJsonFilesPath)">
<!-- DSC v2 PowerShell module files -->
<Component Id="PowerToysDSCReference" Guid="40869ACB-0BEB-4911-AE41-5E73BC1586A9" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="DSCModulesReference" Value="" KeyPath="yes" />
</RegistryKey>
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psd1" Id="PTConfReference.psd1" />
<File Source="$(var.RepoDir)\src\dsc\Microsoft.PowerToys.Configure\Generated\Microsoft.PowerToys.Configure\$(var.Version).0\Microsoft.PowerToys.Configure.psm1" Id="PTConfReference.psm1" />
</Component>
<!-- DSC v3 JSON manifest files - Generated by generateAllFileComponents.ps1 -->
<!--DscJsonFiles_Component_Def-->
</DirectoryRef>
<ComponentGroup Id="DscResourcesComponentGroup">
<ComponentRef Id="PowerToysDSCReference" />
<Component Id="RemoveDSCModulesFolder" Guid="A3C77D92-4E97-4C1A-9F2E-8B3C5D6E7F80" Directory="DSCModulesReferenceFolder">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveDSCModulesFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveDSCModulesReferenceFolder" Directory="DSCModulesReferenceFolder" On="uninstall" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -14,6 +14,7 @@ SET PTRoot=$(SolutionDir)\..
call "..\..\..\publish.cmd" x64
)
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" -Platform "$(Platform)" -nugetHeatPath "$(NUGET_PACKAGES)\wixtoolset.heat\5.0.2"
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)' != 'x64'">
@@ -24,6 +25,7 @@ SET PTRoot=$(SolutionDir)\..
call "..\..\..\publish.cmd" arm64
)
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs" -Platform "$(Platform)" -nugetHeatPath "$(NUGET_PACKAGES)\wixtoolset.heat\5.0.2"
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateDscResourcesWxs.ps1 -dscWxsFile "$(MSBuildThisFileDirectory)\DscResources.wxs" -Platform "$(Platform)" -Configuration "$(Configuration)"
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
@@ -35,7 +37,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\CmdPal.wxs.bk ..\..\..\CmdPal.wxs
call move /Y ..\..\..\ColorPicker.wxs.bk ..\..\..\ColorPicker.wxs
call move /Y ..\..\..\Core.wxs.bk ..\..\..\Core.wxs
call move /Y ..\..\..\DscResources.wxs.bk ..\..\..\DscResources.wxs
call move /Y ..\..\..\EnvironmentVariables.wxs.bk ..\..\..\EnvironmentVariables.wxs
call move /Y ..\..\..\FileExplorerPreview.wxs.bk ..\..\..\FileExplorerPreview.wxs
call move /Y ..\..\..\FileLocksmith.wxs.bk ..\..\..\FileLocksmith.wxs
@@ -59,12 +60,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\Workspaces.wxs.bk ..\..\..\Workspaces.wxs
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(RunBuildEvents)'=='false'">
<PostBuildEvent></PostBuildEvent>
<RunPostBuildEvent></RunPostBuildEvent>
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
<PostBuildEventUseInBuild>false</PostBuildEventUseInBuild>
</PropertyGroup>
<PropertyGroup Label="UserMacros" Condition=" '$(PerUser)' == 'true' ">
<DefineConstants>$(DefineConstants);PerUser=true</DefineConstants>
</PropertyGroup>

View File

@@ -112,7 +112,6 @@
<Custom Action="SetUninstallCommandNotFoundParam" Before="UninstallCommandNotFound" />
<Custom Action="SetUpgradeCommandNotFoundParam" Before="UpgradeCommandNotFound" />
<Custom Action="SetApplyModulesRegistryChangeSetsParam" Before="ApplyModulesRegistryChangeSets" />
<Custom Action="SetInstallPackageIdentityMSIXParam" Before="InstallPackageIdentityMSIX" />
<?if $(var.PerUser) = "true" ?>
<Custom Action="SetInstallDSCModuleParam" Before="InstallDSCModule" />
@@ -120,11 +119,10 @@
<Custom Action="SetUnApplyModulesRegistryChangeSetsParam" Before="UnApplyModulesRegistryChangeSets" />
<Custom Action="CheckGPO" After="InstallInitialize" Condition="NOT Installed" />
<Custom Action="SetBundleInstallLocationData" Before="SetBundleInstallLocation" Condition="NOT Installed OR WIX_UPGRADE_DETECTED" />
<Custom Action="SetBundleInstallLocation" After="InstallFiles" Condition="NOT Installed OR WIX_UPGRADE_DETECTED" />
<Custom Action="SetBundleInstallLocationData" Before="SetBundleInstallLocation" Condition="NOT Installed" />
<Custom Action="SetBundleInstallLocation" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="ApplyModulesRegistryChangeSets" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="InstallCmdPalPackage" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="InstallPackageIdentityMSIX" After="InstallFiles" Condition="NOT Installed" />
<Custom Action="override Wix4CloseApplications_$(sys.BUILDARCHSHORT)" Before="RemoveFiles" />
<Custom Action="RemovePowerToysSchTasks" After="RemoveFiles" />
<!-- TODO: Use to activate embedded MSIX -->
@@ -146,7 +144,6 @@
<Custom Action="UnRegisterCmdPalPackage" Before="RemoveFiles" Condition="Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="UninstallCommandNotFound" Before="RemoveFiles" Condition="Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="UpgradeCommandNotFound" After="InstallFiles" Condition="WIX_UPGRADE_DETECTED" />
<Custom Action="UninstallPackageIdentityMSIX" Before="RemoveFiles" Condition="Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE=&quot;ALL&quot;)" />
<Custom Action="UninstallServicesTask" After="InstallFinalize" Condition="Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE=&quot;ALL&quot;)" />
<!-- TODO: Use to activate embedded MSIX -->
<!--<Custom Action="UninstallEmbeddedMSIXTask" After="InstallFinalize">
@@ -202,12 +199,6 @@
<CustomAction Id="UninstallEmbeddedMSIXTask" Return="ignore" Impersonate="yes" DllEntry="UninstallEmbeddedMSIXCA" BinaryRef="PTCustomActions" />
<CustomAction Id="SetInstallPackageIdentityMSIXParam" Property="InstallPackageIdentityMSIX" Value="[INSTALLFOLDER];[InstallScope]" />
<CustomAction Id="InstallPackageIdentityMSIX" Return="ignore" Impersonate="yes" Execute="deferred" DllEntry="InstallPackageIdentityMSIXCA" BinaryRef="PTCustomActions" />
<CustomAction Id="UninstallPackageIdentityMSIX" Return="ignore" Impersonate="yes" DllEntry="UninstallPackageIdentityMSIXCA" BinaryRef="PTCustomActions" />
<CustomAction Id="InstallDSCModule" Return="ignore" Impersonate="yes" Execute="deferred" DllEntry="InstallDSCModuleCA" BinaryRef="PTCustomActions" />
<CustomAction Id="UninstallDSCModule" Return="ignore" Impersonate="yes" DllEntry="UninstallDSCModuleCA" BinaryRef="PTCustomActions" />

View File

@@ -14,16 +14,11 @@
<?define SettingsV2OOBEAssetsFluentIconsFiles=?>
<?define SettingsV2OOBEAssetsFluentIconsFilesPath=$(var.BinDir)WinUI3Apps\Assets\Settings\Icons\?>
<?define SettingsV2IconsModelsFiles=?>
<?define SettingsV2IconsModelsFilesPath=$(var.BinDir)WinUI3Apps\Assets\Settings\Icons\Models\?>
<Fragment>
<DirectoryRef Id="WinUI3AppsAssetsFolder">
<Directory Id="SettingsV2AssetsInstallFolder" Name="Settings">
<Directory Id="SettingsAppAssetsScriptsFolder" Name="Scripts" />
<Directory Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" Name="Icons">
<Directory Id="SettingsV2IconsModelsInstallFolder" Name="Models" />
</Directory>
<Directory Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" Name="Icons" />
<Directory Id="SettingsV2AssetsModulesInstallFolder" Name="Modules">
<Directory Id="SettingsV2OOBEAssetsModulesInstallFolder" Name="OOBE" />
</Directory>
@@ -50,11 +45,6 @@
<!--SettingsV2OOBEAssetsFluentIconsFiles_Component_Def-->
</DirectoryRef>
<DirectoryRef Id="SettingsV2IconsModelsInstallFolder" FileSource="$(var.SettingsV2IconsModelsFilesPath)">
<!-- Generated by generateFileComponents.ps1 -->
<!--SettingsV2IconsModelsFiles_Component_Def-->
</DirectoryRef>
<DirectoryRef Id="SettingsAppAssetsScriptsFolder" FileSource="$(var.SettingsV2AssetsFilesPath)\Scripts\">
<Component Id="CommandNotFound_Scripts" Guid="898EFA1E-EDD3-4F4B-8C7F-4A14B0D05B02" Bitness="always64">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
@@ -77,7 +67,6 @@
</RegistryKey>
<RemoveFolder Id="RemoveFolderSettingsV2AssetsInstallFolder" Directory="SettingsV2AssetsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2OOBEAssetsFluentIconsInstallFolder" Directory="SettingsV2OOBEAssetsFluentIconsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2IconsModelsInstallFolder" Directory="SettingsV2IconsModelsInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2AssetsModulesInstallFolder" Directory="SettingsV2AssetsModulesInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsV2OOBEAssetsModulesInstallFolder" Directory="SettingsV2OOBEAssetsModulesInstallFolder" On="uninstall" />
<RemoveFolder Id="RemoveFolderSettingsAppAssetsScriptsFolder" Directory="SettingsAppAssetsScriptsFolder" On="uninstall" />

View File

@@ -1,7 +1,9 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, Position = 1)]
[string]$platform
[string]$platform,
[Parameter(Mandatory = $False, Position = 2)]
[string]$installscopeperuser = "false"
)
Function Generate-FileList() {
@@ -75,7 +77,9 @@ Function Generate-FileComponents() {
[Parameter(Mandatory = $True, Position = 1)]
[string]$fileListName,
[Parameter(Mandatory = $True, Position = 2)]
[string]$wxsFilePath
[string]$wxsFilePath,
[Parameter(Mandatory = $True, Position = 3)]
[string]$regroot
)
$wxsFile = Get-Content $wxsFilePath;
@@ -96,7 +100,7 @@ Function Generate-FileComponents() {
$componentDefs +=
@"
<Component Id="$($componentId)" Guid="$((New-Guid).ToString().ToUpper())">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryKey Root="$($regroot)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$($componentId)" Value="" KeyPath="yes"/>
</RegistryKey>`r`n
"@
@@ -130,194 +134,194 @@ if ($platform -ceq "arm64") {
$platform = "ARM64"
}
if ($installscopeperuser -eq "true") {
$registryroot = "HKCU"
} else {
$registryroot = "HKLM"
}
#BaseApplications
Generate-FileList -fileDepsJson "" -fileListName BaseApplicationsFiles -wxsFilePath $PSScriptRoot\BaseApplications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release"
Generate-FileComponents -fileListName "BaseApplicationsFiles" -wxsFilePath $PSScriptRoot\BaseApplications.wxs
Generate-FileComponents -fileListName "BaseApplicationsFiles" -wxsFilePath $PSScriptRoot\BaseApplications.wxs -regroot $registryroot
#WinUI3Applications
Generate-FileList -fileDepsJson "" -fileListName WinUI3ApplicationsFiles -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps"
Generate-FileComponents -fileListName "WinUI3ApplicationsFiles" -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs
Generate-FileComponents -fileListName "WinUI3ApplicationsFiles" -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -regroot $registryroot
#AdvancedPaste
Generate-FileList -fileDepsJson "" -fileListName AdvancedPasteAssetsFiles -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\AdvancedPaste"
Generate-FileComponents -fileListName "AdvancedPasteAssetsFiles" -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs
Generate-FileComponents -fileListName "AdvancedPasteAssetsFiles" -wxsFilePath $PSScriptRoot\AdvancedPaste.wxs -regroot $registryroot
#AwakeFiles
Generate-FileList -fileDepsJson "" -fileListName AwakeImagesFiles -wxsFilePath $PSScriptRoot\Awake.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Awake"
Generate-FileComponents -fileListName "AwakeImagesFiles" -wxsFilePath $PSScriptRoot\Awake.wxs
Generate-FileComponents -fileListName "AwakeImagesFiles" -wxsFilePath $PSScriptRoot\Awake.wxs -regroot $registryroot
#ColorPicker
Generate-FileList -fileDepsJson "" -fileListName ColorPickerAssetsFiles -wxsFilePath $PSScriptRoot\ColorPicker.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\ColorPicker"
Generate-FileComponents -fileListName "ColorPickerAssetsFiles" -wxsFilePath $PSScriptRoot\ColorPicker.wxs
Generate-FileComponents -fileListName "ColorPickerAssetsFiles" -wxsFilePath $PSScriptRoot\ColorPicker.wxs -regroot $registryroot
#Environment Variables
Generate-FileList -fileDepsJson "" -fileListName EnvironmentVariablesAssetsFiles -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\EnvironmentVariables"
Generate-FileComponents -fileListName "EnvironmentVariablesAssetsFiles" -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs
Generate-FileComponents -fileListName "EnvironmentVariablesAssetsFiles" -wxsFilePath $PSScriptRoot\EnvironmentVariables.wxs -regroot $registryroot
#FileExplorerAdd-ons
Generate-FileList -fileDepsJson "" -fileListName MonacoPreviewHandlerMonacoAssetsFiles -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Monaco"
Generate-FileList -fileDepsJson "" -fileListName MonacoPreviewHandlerCustomLanguagesFiles -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Monaco\customLanguages"
Generate-FileComponents -fileListName "MonacoPreviewHandlerMonacoAssetsFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
Generate-FileComponents -fileListName "MonacoPreviewHandlerCustomLanguagesFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
Generate-FileComponents -fileListName "MonacoPreviewHandlerMonacoAssetsFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -regroot $registryroot
Generate-FileComponents -fileListName "MonacoPreviewHandlerCustomLanguagesFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs -regroot $registryroot
#FileLocksmith
Generate-FileList -fileDepsJson "" -fileListName FileLocksmithAssetsFiles -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\FileLocksmith"
Generate-FileComponents -fileListName "FileLocksmithAssetsFiles" -wxsFilePath $PSScriptRoot\FileLocksmith.wxs
Generate-FileComponents -fileListName "FileLocksmithAssetsFiles" -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -regroot $registryroot
#Hosts
Generate-FileList -fileDepsJson "" -fileListName HostsAssetsFiles -wxsFilePath $PSScriptRoot\Hosts.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Hosts"
Generate-FileComponents -fileListName "HostsAssetsFiles" -wxsFilePath $PSScriptRoot\Hosts.wxs
Generate-FileComponents -fileListName "HostsAssetsFiles" -wxsFilePath $PSScriptRoot\Hosts.wxs -regroot $registryroot
#ImageResizer
Generate-FileList -fileDepsJson "" -fileListName ImageResizerAssetsFiles -wxsFilePath $PSScriptRoot\ImageResizer.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\ImageResizer"
Generate-FileComponents -fileListName "ImageResizerAssetsFiles" -wxsFilePath $PSScriptRoot\ImageResizer.wxs
Generate-FileComponents -fileListName "ImageResizerAssetsFiles" -wxsFilePath $PSScriptRoot\ImageResizer.wxs -regroot $registryroot
# Light Switch Service
Generate-FileList -fileDepsJson "" -fileListName LightSwitchFiles -wxsFilePath $PSScriptRoot\LightSwitch.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\LightSwitchService"
Generate-FileComponents -fileListName "LightSwitchFiles" -wxsFilePath $PSScriptRoot\LightSwitch.wxs
Generate-FileComponents -fileListName "LightSwitchFiles" -wxsFilePath $PSScriptRoot\LightSwitch.wxs -regroot $registryroot
#New+
Generate-FileList -fileDepsJson "" -fileListName NewPlusAssetsFiles -wxsFilePath $PSScriptRoot\NewPlus.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\NewPlus"
Generate-FileComponents -fileListName "NewPlusAssetsFiles" -wxsFilePath $PSScriptRoot\NewPlus.wxs
Generate-FileComponents -fileListName "NewPlusAssetsFiles" -wxsFilePath $PSScriptRoot\NewPlus.wxs -regroot $registryroot
#Peek
Generate-FileList -fileDepsJson "" -fileListName PeekAssetsFiles -wxsFilePath $PSScriptRoot\Peek.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Peek\"
Generate-FileComponents -fileListName "PeekAssetsFiles" -wxsFilePath $PSScriptRoot\Peek.wxs
Generate-FileComponents -fileListName "PeekAssetsFiles" -wxsFilePath $PSScriptRoot\Peek.wxs -regroot $registryroot
#PowerRename
Generate-FileList -fileDepsJson "" -fileListName PowerRenameAssetsFiles -wxsFilePath $PSScriptRoot\PowerRename.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\PowerRename\"
Generate-FileComponents -fileListName "PowerRenameAssetsFiles" -wxsFilePath $PSScriptRoot\PowerRename.wxs
Generate-FileComponents -fileListName "PowerRenameAssetsFiles" -wxsFilePath $PSScriptRoot\PowerRename.wxs -regroot $registryroot
#RegistryPreview
Generate-FileList -fileDepsJson "" -fileListName RegistryPreviewAssetsFiles -wxsFilePath $PSScriptRoot\RegistryPreview.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\RegistryPreview\"
Generate-FileComponents -fileListName "RegistryPreviewAssetsFiles" -wxsFilePath $PSScriptRoot\RegistryPreview.wxs
Generate-FileComponents -fileListName "RegistryPreviewAssetsFiles" -wxsFilePath $PSScriptRoot\RegistryPreview.wxs -regroot $registryroot
#Run
Generate-FileList -fileDepsJson "" -fileListName launcherImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\PowerLauncher"
Generate-FileComponents -fileListName "launcherImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "launcherImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
## Plugins
###Calculator
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Calculator\Microsoft.PowerToys.Run.Plugin.Calculator.deps.json" -fileListName calcComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName calcImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Calculator\Images"
Generate-FileComponents -fileListName "calcComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "calcImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "calcComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "calcImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Folder
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Folder\Microsoft.Plugin.Folder.deps.json" -fileListName FolderComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName FolderImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Folder\Images"
Generate-FileComponents -fileListName "FolderComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "FolderImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "FolderComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "FolderImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Program
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Program\Microsoft.Plugin.Program.deps.json" -fileListName ProgramComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ProgramImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Program\Images"
Generate-FileComponents -fileListName "ProgramComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ProgramImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ProgramComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ProgramImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Shell
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Shell\Microsoft.Plugin.Shell.deps.json" -fileListName ShellComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ShellImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Shell\Images"
Generate-FileComponents -fileListName "ShellComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ShellImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ShellComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ShellImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Indexer
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Indexer\Microsoft.Plugin.Indexer.deps.json" -fileListName IndexerComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName IndexerImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Indexer\Images"
Generate-FileComponents -fileListName "IndexerComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "IndexerImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "IndexerComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "IndexerImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###UnitConverter
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.deps.json" -fileListName UnitConvCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName UnitConvImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\UnitConverter\Images"
Generate-FileComponents -fileListName "UnitConvCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UnitConvImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UnitConvCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "UnitConvImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###WebSearch
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WebSearch\Community.PowerToys.Run.Plugin.WebSearch.deps.json" -fileListName WebSrchCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WebSrchImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WebSearch\Images"
Generate-FileComponents -fileListName "WebSrchCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WebSrchImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WebSrchCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WebSrchImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###History
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\History\Microsoft.PowerToys.Run.Plugin.History.deps.json" -fileListName HistoryPluginComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName HistoryPluginImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\History\Images"
Generate-FileComponents -fileListName "HistoryPluginComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "HistoryPluginImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "HistoryPluginComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "HistoryPluginImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Uri
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Uri\Microsoft.Plugin.Uri.deps.json" -fileListName UriComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName UriImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Uri\Images"
Generate-FileComponents -fileListName "UriComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UriImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "UriComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "UriImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###VSCodeWorkspaces
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\VSCodeWorkspaces\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.deps.json" -fileListName VSCWrkCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName VSCWrkImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\VSCodeWorkspaces\Images"
Generate-FileComponents -fileListName "VSCWrkCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "VSCWrkImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "VSCWrkCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "VSCWrkImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###WindowWalker
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowWalker\Microsoft.Plugin.WindowWalker.deps.json" -fileListName WindowWlkrCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WindowWlkrImagesCompFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowWalker\Images"
Generate-FileComponents -fileListName "WindowWlkrCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WindowWlkrImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WindowWlkrCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WindowWlkrImagesCompFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###OneNote
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\OneNote\Microsoft.PowerToys.Run.Plugin.OneNote.deps.json" -fileListName OneNoteComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName OneNoteImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\OneNote\Images"
Generate-FileComponents -fileListName "OneNoteComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "OneNoteImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "OneNoteComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "OneNoteImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Registry
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Registry\Microsoft.PowerToys.Run.Plugin.Registry.deps.json" -fileListName RegistryComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName RegistryImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Registry\Images"
Generate-FileComponents -fileListName "RegistryComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "RegistryImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "RegistryComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "RegistryImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###Service
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Service\Microsoft.PowerToys.Run.Plugin.Service.deps.json" -fileListName ServiceComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ServiceImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\Service\Images"
Generate-FileComponents -fileListName "ServiceComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ServiceImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ServiceComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ServiceImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###System
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\System\Microsoft.PowerToys.Run.Plugin.System.deps.json" -fileListName SystemComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName SystemImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\System\Images"
Generate-FileComponents -fileListName "SystemComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "SystemImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "SystemComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SystemImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###TimeDate
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\TimeDate\Microsoft.PowerToys.Run.Plugin.TimeDate.deps.json" -fileListName TimeDateComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName TimeDateImagesComponentFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\TimeDate\Images"
Generate-FileComponents -fileListName "TimeDateComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "TimeDateImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "TimeDateComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "TimeDateImagesComponentFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###WindowsSettings
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.deps.json" -fileListName WinSetCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WinSetImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsSettings\Images"
Generate-FileComponents -fileListName "WinSetCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinSetImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinSetCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinSetImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###WindowsTerminal
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.deps.json" -fileListName WinTermCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName WinTermImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\WindowsTerminal\Images"
Generate-FileComponents -fileListName "WinTermCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinTermImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "WinTermCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "WinTermImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###PowerToys
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\PowerToys\Microsoft.PowerToys.Run.Plugin.PowerToys.deps.json" -fileListName PowerToysCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName PowerToysImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\PowerToys\Images"
Generate-FileComponents -fileListName "PowerToysCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "PowerToysImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "PowerToysCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "PowerToysImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
###ValueGenerator
Generate-FileList -fileDepsJson "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\ValueGenerator\Community.PowerToys.Run.Plugin.ValueGenerator.deps.json" -fileListName ValueGeneratorCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1
Generate-FileList -fileDepsJson "" -fileListName ValueGeneratorImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\RunPlugins\ValueGenerator\Images"
Generate-FileComponents -fileListName "ValueGeneratorCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ValueGeneratorImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs
Generate-FileComponents -fileListName "ValueGeneratorCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
Generate-FileComponents -fileListName "ValueGeneratorImagesCmpFiles" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot
## Plugins
#ShortcutGuide
Generate-FileList -fileDepsJson "" -fileListName ShortcutGuideSvgFiles -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\ShortcutGuide\"
Generate-FileComponents -fileListName "ShortcutGuideSvgFiles" -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs
Generate-FileComponents -fileListName "ShortcutGuideSvgFiles" -wxsFilePath $PSScriptRoot\ShortcutGuide.wxs -regroot $registryroot
#Settings
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2AssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Modules\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsModulesFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Modules\OOBE\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2OOBEAssetsFluentIconsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Icons\"
Generate-FileList -fileDepsJson "" -fileListName SettingsV2IconsModelsFiles -wxsFilePath $PSScriptRoot\Settings.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Settings\Icons\Models\"
Generate-FileComponents -fileListName "SettingsV2AssetsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2AssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsFluentIconsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2IconsModelsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs
Generate-FileComponents -fileListName "SettingsV2AssetsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2AssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsModulesFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
Generate-FileComponents -fileListName "SettingsV2OOBEAssetsFluentIconsFiles" -wxsFilePath $PSScriptRoot\Settings.wxs -regroot $registryroot
#Workspaces
Generate-FileList -fileDepsJson "" -fileListName WorkspacesImagesComponentFiles -wxsFilePath $PSScriptRoot\Workspaces.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\Workspaces\"
Generate-FileComponents -fileListName "WorkspacesImagesComponentFiles" -wxsFilePath $PSScriptRoot\Workspaces.wxs
#DSC Resources - JSON manifest files in DSCModules subfolder
Generate-FileList -fileDepsJson "" -fileListName DscJsonFiles -wxsFilePath $PSScriptRoot\DscResources.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\DSCModules\"
Generate-FileComponents -fileListName "DscJsonFiles" -wxsFilePath $PSScriptRoot\DscResources.wxs
Generate-FileComponents -fileListName "WorkspacesImagesComponentFiles" -wxsFilePath $PSScriptRoot\Workspaces.wxs -regroot $registryroot

View File

@@ -0,0 +1,102 @@
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True)]
[string]$dscWxsFile,
[Parameter(Mandatory = $True)]
[string]$Platform,
[Parameter(Mandatory = $True)]
[string]$Configuration
)
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
# Find build output directory
$buildOutputDir = Join-Path $scriptDir "..\..\$Platform\$Configuration"
if (-not (Test-Path $buildOutputDir)) {
Write-Error "Build output directory not found: '$buildOutputDir'"
exit 1
}
# Find all DSC manifest JSON files
$dscFiles = Get-ChildItem -Path $buildOutputDir -Filter "microsoft.powertoys.*.settings.dsc.resource.json" -File
if (-not $dscFiles) {
Write-Warning "No DSC manifest files found in '$buildOutputDir'"
# Create empty component group
$wxsContent = @"
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
</ComponentGroup>
</Fragment>
</Wix>
"@
Set-Content -Path $dscWxsFile -Value $wxsContent
exit 0
}
Write-Host "Found $($dscFiles.Count) DSC manifest file(s)"
# Generate WiX fragment
$wxsContent = @"
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include `$(sys.CURRENTDIR)\Common.wxi?>
<Fragment>
<DirectoryRef Id="DSCModulesReferenceFolder">
"@
$componentRefs = @()
foreach ($file in $dscFiles) {
$componentId = "DscResource_" + ($file.BaseName -replace '[^A-Za-z0-9_]', '_')
$fileId = $componentId + "_File"
$guid = [System.Guid]::NewGuid().ToString().ToUpper()
$componentRefs += $componentId
$wxsContent += @"
<Component Id="$componentId" Guid="{$guid}" Directory="DSCModulesReferenceFolder">
<RegistryKey Root="`$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="$componentId" Value="" KeyPath="yes"/>
</RegistryKey>
<File Id="$fileId" Source="`$(var.BinDir)$($file.Name)" Vital="no"/>
</Component>
"@
}
$wxsContent += @"
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="DscResourcesComponentGroup">
"@
foreach ($componentId in $componentRefs) {
$wxsContent += @"
<ComponentRef Id="$componentId"/>
"@
}
$wxsContent += @"
</ComponentGroup>
</Fragment>
</Wix>
"@
# Write the WiX file
Set-Content -Path $dscWxsFile -Value $wxsContent
Write-Host "Generated DSC resources WiX fragment: '$dscWxsFile'"

View File

@@ -1,70 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Sparse package manifest (moved to PackageIdentity folder for cleaner organization).
Based on Windows AI Foundry WPF sparse sample with PowerOCR customizations. -->
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
xmlns:systemai="http://schemas.microsoft.com/appx/manifest/systemai/windows10"
IgnorableNamespaces="uap uap2 uap3 rescap desktop uap10 systemai">
<Identity
Name="Microsoft.PowerToys.SparseApp"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="0.0.1.0" />
<Properties>
<DisplayName>PowerToys.SparseApp</DisplayName>
<PublisherDisplayName>PowerToys</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>
<Resources>
<Resource Language="en-us" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19000.0" MaxVersionTested="10.0.26226.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<systemai:Capability Name="systemAIModels"/>
<rescap:Capability Name="unvirtualizedResources"/>
</Capabilities>
<Applications>
<Application Id="PowerToys.OCR" Executable="PowerToys.PowerOCR.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
DisplayName="PowerToys.OCR"
Description="PowerToys OCR Module"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png"
AppListEntry="none">
</uap:VisualElements>
</Application>
<Application Id="PowerToys.SettingsUI" Executable="WinUI3Apps\PowerToys.Settings.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
DisplayName="PowerToys.SettingsUI"
Description="PowerToys Settings UI"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png"
AppListEntry="none">
</uap:VisualElements>
</Application>
<Application Id="PowerToys.ImageResizerUI" Executable="WinUI3Apps\PowerToys.ImageResizer.exe" EntryPoint="Windows.FullTrustApplication">
<uap:VisualElements
DisplayName="PowerToys.ImageResizer"
Description="PowerToys Image Resizer UI"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png"
AppListEntry="none">
</uap:VisualElements>
</Application>
</Applications>
</Package>

View File

@@ -1,6 +0,0 @@
@echo off
REM Wrapper to invoke PowerToys sparse package build script.
REM Pass through all arguments (e.g. Platform=arm64 Configuration=Debug -Clean)
powershell -ExecutionPolicy Bypass -NoLogo -NoProfile -File "%~dp0\BuildSparsePackage.ps1" %*
exit /b %ERRORLEVEL%

View File

@@ -1,422 +0,0 @@
#Requires -Version 5.1
[CmdletBinding()]
Param(
[Parameter(Mandatory=$false)]
[ValidateSet("arm64", "x64")]
[string]$Platform = "x64",
[Parameter(Mandatory=$false)]
[ValidateSet("Debug", "Release")]
[string]$Configuration = "Release",
[switch]$Clean,
[switch]$ForceCert,
[switch]$NoSign,
[switch]$CIBuild
)
# PowerToys sparse packaging helper.
# Generates a sparse MSIX (no payload) that grants package identity to selected Win32 components.
# Multiple applications (PowerOCR, Settings UI, etc.) can share this single sparse identity.
$ErrorActionPreference = 'Stop'
$isCIBuild = $false
if ($CIBuild.IsPresent) {
$isCIBuild = $true
} elseif ($env:CIBuild) {
$isCIBuild = $env:CIBuild -ieq 'true'
}
$currentPublisherHint = $script:Config.CertSubject
# Configuration constants - centralized management
$script:Config = @{
IdentityName = "Microsoft.PowerToys.SparseApp"
SparseMsixName = "PowerToysSparse.msix"
CertPrefix = "PowerToysSparse"
CertSubject = 'CN=PowerToys Dev, O=PowerToys, L=Redmond, S=Washington, C=US'
CertValidMonths = 12
}
#region Helper Functions
function Find-WindowsSDKTool {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$ToolName,
[Parameter(Mandatory=$false)]
[string]$Architecture = "x64"
)
# Simple fallback: check common Windows SDK locations
$commonPaths = @(
"${env:ProgramFiles}\Windows Kits\10\bin\*\$Architecture\$ToolName",
"${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\$Architecture\$ToolName",
"${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x86\$ToolName" # SignTool fallback
)
foreach ($pattern in $commonPaths) {
$found = Get-ChildItem $pattern -ErrorAction SilentlyContinue |
Sort-Object Name -Descending |
Select-Object -First 1
if ($found) {
Write-BuildLog "Found $ToolName at: $($found.FullName)" -Level Info
return $found.FullName
}
}
throw "$ToolName not found. Please ensure Windows SDK is installed."
}
function Test-CertificateValidity {
param([string]$ThumbprintFile)
if (-not (Test-Path $ThumbprintFile)) { return $false }
try {
$thumb = (Get-Content $ThumbprintFile -Raw).Trim()
if (-not $thumb) { return $false }
$cert = Get-Item "cert:\CurrentUser\My\$thumb" -ErrorAction Stop
return $cert.HasPrivateKey -and $cert.NotAfter -gt (Get-Date)
} catch {
return $false
}
}
function Write-BuildLog {
param([string]$Message, [string]$Level = "Info")
$colors = @{ Error = "Red"; Warning = "Yellow"; Success = "Green"; Info = "Cyan" }
$color = if ($colors.ContainsKey($Level)) { $colors[$Level] } else { "White" }
Write-Host "[$(Get-Date -f 'HH:mm:ss')] $Message" -ForegroundColor $color
}
function Stop-FileProcesses {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$FilePath
)
# This function is kept for compatibility but simplified since
# the staging directory approach resolves the file lock issues
Write-Verbose "File process check for: $FilePath"
}
#endregion
# Environment diagnostics for troubleshooting
Write-BuildLog "Starting PackageIdentity build process..." -Level Info
Write-BuildLog "PowerShell Version: $($PSVersionTable.PSVersion)" -Level Info
try {
$execPolicy = Get-ExecutionPolicy
Write-BuildLog "Execution Policy: $execPolicy" -Level Info
} catch {
Write-BuildLog "Execution Policy: Unable to determine (MSBuild environment)" -Level Info
}
Write-BuildLog "Current User: $env:USERNAME" -Level Info
Write-BuildLog "Build Platform: $Platform, Configuration: $Configuration" -Level Info
# Check for Visual Studio environment
if ($env:VSINSTALLDIR) {
Write-BuildLog "Running in Visual Studio environment: $env:VSINSTALLDIR" -Level Info
}
# Ensure certificate provider is available
try {
# Force load certificate provider for MSBuild environment
if (-not (Get-PSProvider -PSProvider Certificate -ErrorAction SilentlyContinue)) {
Write-BuildLog "Loading certificate provider..." -Level Warning
Import-Module Microsoft.PowerShell.Security -Force
}
if (-not (Test-Path 'Cert:\CurrentUser')) {
Write-BuildLog "Certificate drive not available, attempting to initialize..." -Level Warning
Import-Module PKI -ErrorAction SilentlyContinue
# Try to access the certificate store to force initialization
Get-ChildItem "Cert:\CurrentUser\My" -ErrorAction SilentlyContinue | Out-Null
}
} catch {
Write-BuildLog ("Note: Certificate provider setup may need manual configuration: {0}" -f $_) -Level Warning
}
# Project root folder (now set to current script folder for local builds)
$ProjectRoot = $PSScriptRoot
$UserFolder = Join-Path $ProjectRoot '.user'
if (-not (Test-Path $UserFolder)) { New-Item -ItemType Directory -Path $UserFolder | Out-Null }
# Certificate file paths using configuration
$prefix = $script:Config.CertPrefix
$CertThumbFile, $CertCerFile = @('.thumbprint', '.cer') |
ForEach-Object { Join-Path $UserFolder "$prefix.certificate.sample$_" }
# Clean option: remove bin/obj and uninstall existing sparse package if present
if ($Clean) {
Write-BuildLog "Cleaning build artifacts..." -Level Info
'bin','obj' | ForEach-Object {
$target = Join-Path $ProjectRoot $_
if (Test-Path $target) { Remove-Item $target -Recurse -Force }
}
Write-BuildLog "Attempting to remove existing sparse package (best effort)" -Level Info
try { Get-AppxPackage -Name $script:Config.IdentityName | Remove-AppxPackage } catch {}
}
# Force certificate regeneration if requested
if ($ForceCert -and (Test-Path $UserFolder)) {
Write-BuildLog "ForceCert specified: removing existing certificate artifacts..." -Level Warning
Remove-Item $UserFolder -Recurse -Force
New-Item -ItemType Directory -Path $UserFolder | Out-Null
}
# Ensure dev cert (development only; not for production use) - skip if NoSign specified
$needNewCert = -not $NoSign -and (-not (Test-Path $CertThumbFile) -or $ForceCert -or -not (Test-CertificateValidity -ThumbprintFile $CertThumbFile))
if ($needNewCert) {
Write-BuildLog "Generating development certificate (prefix=$($script:Config.CertPrefix))..." -Level Info
# Clear stale files in the certificate cache
if (Test-Path $UserFolder) {
Get-ChildItem -Path $UserFolder | ForEach-Object {
if ($_.PSIsContainer) {
Remove-Item $_.FullName -Recurse -Force
} else {
Remove-Item $_.FullName -Force
}
}
}
if (-not (Test-Path $UserFolder)) {
New-Item -ItemType Directory -Path $UserFolder | Out-Null
}
$now = Get-Date
$expiration = $now.AddMonths($script:Config.CertValidMonths)
# Subject MUST match <Identity Publisher="..."> inside AppxManifest.xml
$friendlyName = "PowerToys Dev Sparse Cert Create=$now"
$keyFriendly = "PowerToys Dev Sparse Key Create=$now"
$certStore = 'cert:\CurrentUser\My'
$ekuOid = '2.5.29.37'
$ekuValue = '1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13'
$eku = "$ekuOid={text}$ekuValue"
$cert = New-SelfSignedCertificate -CertStoreLocation $certStore `
-NotAfter $expiration `
-Subject $script:Config.CertSubject `
-FriendlyName $friendlyName `
-KeyFriendlyName $keyFriendly `
-KeyDescription $keyFriendly `
-TextExtension $eku
# Export certificate files
Set-Content -Path $CertThumbFile -Value $cert.Thumbprint -Force
Export-Certificate -Cert $cert -FilePath $CertCerFile -Force | Out-Null
}
# Determine output directory - using PowerToys standard structure
# Navigate to PowerToys root (two levels up from src/PackageIdentity)
$PowerToysRoot = Split-Path (Split-Path $ProjectRoot -Parent) -Parent
$outDir = Join-Path $PowerToysRoot "$Platform\$Configuration"
if (-not (Test-Path $outDir)) {
Write-BuildLog "Creating output directory: $outDir" -Level Info
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
}
# PackageIdentity folder (this script location) containing the sparse manifest and assets
$sparseDir = $PSScriptRoot
$manifestPath = Join-Path $sparseDir 'AppxManifest.xml'
if (-not (Test-Path $manifestPath)) { throw "Missing AppxManifest.xml in PackageIdentity folder: $manifestPath" }
$versionPropsPath = Join-Path $PowerToysRoot 'src\Version.props'
$targetManifestVersion = $null
$versionCandidate = $null
if (Test-Path $versionPropsPath) {
try {
[xml]$propsXml = Get-Content -Path $versionPropsPath -Raw
$versionCandidate = $propsXml.Project.PropertyGroup.Version
} catch {
Write-BuildLog ("Unable to read version from {0}: {1}" -f $versionPropsPath, $_) -Level Warning
}
} else {
Write-BuildLog "Version.props not found at $versionPropsPath; manifest version will remain unchanged." -Level Warning
}
if ($versionCandidate) {
$targetManifestVersion = $versionCandidate.Trim()
if (($targetManifestVersion -split '\.').Count -lt 4) {
$targetManifestVersion = "$targetManifestVersion.0"
}
Write-BuildLog "Using sparse package version from Version.props: $targetManifestVersion" -Level Info
} else {
Write-BuildLog "No version value provided; manifest version will remain unchanged." -Level Info
}
# Find MakeAppx.exe from Windows SDK
try {
$hostSdkArchitecture = if ([System.Environment]::Is64BitProcess) { 'x64' } else { 'x86' }
$makeAppxPath = Find-WindowsSDKTool -ToolName "makeappx.exe" -Architecture $hostSdkArchitecture
} catch {
Write-Error "MakeAppx.exe not found. Please ensure Windows SDK is installed."
exit 1
}
# Pack sparse MSIX from PackageIdentity folder
$msixPath = Join-Path $outDir $script:Config.SparseMsixName
# Clean up existing MSIX file
if (Test-Path $msixPath) {
Write-BuildLog "Removing existing MSIX file..." -Level Info
try {
Remove-Item $msixPath -Force -ErrorAction Stop
Write-BuildLog "Successfully removed existing MSIX file" -Level Success
} catch {
Write-BuildLog ("Warning: Could not remove existing MSIX file: {0}" -f $_) -Level Warning
}
}
# Create a clean staging directory to avoid file lock issues
$stagingDir = Join-Path $outDir "staging"
if (Test-Path $stagingDir) {
Remove-Item $stagingDir -Recurse -Force -ErrorAction SilentlyContinue
}
New-Item -ItemType Directory -Path $stagingDir -Force | Out-Null
try {
Write-BuildLog "Creating clean staging directory for packaging..." -Level Info
# Copy only essential files to staging directory to avoid file locks
$essentialFiles = @(
"AppxManifest.xml"
"Images\*"
)
foreach ($filePattern in $essentialFiles) {
$sourcePath = Join-Path $sparseDir $filePattern
$relativePath = $filePattern
if ($filePattern.Contains('\')) {
$targetDir = Join-Path $stagingDir (Split-Path $relativePath -Parent)
if (-not (Test-Path $targetDir)) {
New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
}
}
if ($filePattern.EndsWith('\*')) {
# Copy directory contents
$sourceDir = $sourcePath.TrimEnd('\*')
$targetDir = Join-Path $stagingDir (Split-Path $relativePath.TrimEnd('\*') -Parent)
if (Test-Path $sourceDir) {
Copy-Item -Path "$sourceDir\*" -Destination $targetDir -Force -ErrorAction SilentlyContinue
}
} else {
# Copy single file
$targetPath = Join-Path $stagingDir $relativePath
if (Test-Path $sourcePath) {
Copy-Item -Path $sourcePath -Destination $targetPath -Force -ErrorAction SilentlyContinue
}
}
}
# Ensure publisher matches the dev certificate for local builds
$manifestStagingPath = Join-Path $stagingDir 'AppxManifest.xml'
$shouldUseDevPublisher = -not $isCIBuild
if (Test-Path $manifestStagingPath) {
try {
[xml]$manifestXml = Get-Content -Path $manifestStagingPath -Raw
$identityNode = $manifestXml.Package.Identity
$manifestChanged = $false
if ($identityNode) {
$currentPublisherHint = $identityNode.Publisher
}
if ($identityNode) {
if ($targetManifestVersion -and $identityNode.Version -ne $targetManifestVersion) {
Write-BuildLog "Updating manifest version to $targetManifestVersion" -Level Info
$identityNode.SetAttribute('Version', $targetManifestVersion)
$manifestChanged = $true
}
if ($shouldUseDevPublisher -and $identityNode.Publisher -ne $script:Config.CertSubject) {
Write-BuildLog "Updating manifest publisher for local build" -Level Warning
$identityNode.SetAttribute('Publisher', $script:Config.CertSubject)
$manifestChanged = $true
}
$currentPublisherHint = $identityNode.Publisher
}
if ($manifestChanged) {
$manifestXml.Save($manifestStagingPath)
}
} catch {
Write-BuildLog ("Unable to adjust manifest metadata: {0}" -f $_) -Level Warning
}
}
Write-BuildLog "Staging directory prepared with essential files only" -Level Success
# Pack MSIX using staging directory
Write-BuildLog "Packing sparse MSIX ($($script:Config.SparseMsixName)) from staging -> $msixPath" -Level Info
& $makeAppxPath pack /d $stagingDir /p $msixPath /nv /o
if ($LASTEXITCODE -eq 0 -and (Test-Path $msixPath)) {
Write-BuildLog "MSIX packaging completed successfully" -Level Success
} else {
Write-BuildLog "MakeAppx failed with exit code $LASTEXITCODE" -Level Error
exit 1
}
} finally {
# Clean up staging directory
if (Test-Path $stagingDir) {
try {
Remove-Item $stagingDir -Recurse -Force -ErrorAction SilentlyContinue
Write-BuildLog "Cleaned up staging directory" -Level Info
} catch {
Write-BuildLog ("Warning: Could not clean up staging directory: {0}" -f $_) -Level Warning
}
}
}
# Sign package (skip if NoSign specified for CI scenarios)
if ($NoSign) {
Write-BuildLog "Skipping signing (NoSign specified for CI build)" -Level Warning
} else {
# Use certificate thumbprint for signing (safer, no password)
$certThumbprint = (Get-Content -Path $CertThumbFile -Raw).Trim()
try {
$signToolPath = Find-WindowsSDKTool -ToolName "signtool.exe"
} catch {
Write-Error "SignTool.exe not found. Please ensure Windows SDK is installed."
exit 1
}
Write-BuildLog "Signing sparse MSIX using cert thumbprint $certThumbprint..." -Level Info
& $signToolPath sign /fd SHA256 /sha1 $certThumbprint $msixPath
if ($LASTEXITCODE -ne 0) {
Write-Warning "SignTool failed (exit $LASTEXITCODE). Ensure the certificate is in CurrentUser\\My and try -ForceCert if needed."
exit $LASTEXITCODE
}
}
$publisherHintFile = Join-Path $UserFolder "$($script:Config.CertPrefix).publisher.txt"
try {
Set-Content -Path $publisherHintFile -Value $currentPublisherHint -Force -NoNewline
} catch {
Write-BuildLog ("Unable to write publisher hint: {0}" -f $_) -Level Warning
}
Write-BuildLog "`nPackage created: $msixPath" -Level Success
if ($NoSign) {
Write-BuildLog "UNSIGNED package created for CI build. Sign before deployment." -Level Warning
} else {
Write-BuildLog "Install the dev certificate (once): $CertCerFile" -Level Info
Write-BuildLog "Identity Name: $($script:Config.IdentityName)" -Level Info
}
Write-BuildLog "Register sparse package:" -Level Info
Write-BuildLog " Add-AppxPackage -Path `"$msixPath`" -ExternalLocation `"$outDir`"" -Level Warning
Write-BuildLog "(If already installed and you changed manifest only): Add-AppxPackage -Register `"$manifestPath`" -ExternalLocation `"$outDir`" -ForceApplicationShutdown" -Level Warning

View File

@@ -1,43 +0,0 @@
<#
.SYNOPSIS
Determine whether a given process (by PID) runs with an MSIX/UWP package identity.
.DESCRIPTION
Calls the Windows API GetPackageFullName to check if the target process executes under an MSIX/Sparse App/UWP package identity.
Returns the package full name when identity is present, or "No package identity" otherwise.
.PARAMETER ProcessId
The process ID to inspect.
.EXAMPLE
.\Check-ProcessIdentity.ps1 -pid 12345
#>
param(
[Parameter(Mandatory=$true)]
[int]$ProcessId
)
Add-Type -TypeDefinition @'
using System;
using System.Text;
using System.Runtime.InteropServices;
public class P {
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr OpenProcess(uint a, bool b, int p);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CloseHandle(IntPtr h);
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern int GetPackageFullName(IntPtr h, ref int l, StringBuilder b);
public static string G(int pid) {
IntPtr h = OpenProcess(0x1000, false, pid);
if (h == IntPtr.Zero) return "Failed to open process";
int len = 0;
GetPackageFullName(h, ref len, null);
if (len == 0) { CloseHandle(h); return "No package identity"; }
var sb = new StringBuilder(len);
int r = GetPackageFullName(h, ref len, sb);
CloseHandle(h);
return r == 0 ? sb.ToString() : "Error:" + r;
}
}
'@
$result = [P]::G($ProcessId)
Write-Output $result

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

View File

@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- CI Build Configuration -->
<PropertyGroup Condition="'$(CIBuild)'=='true'">
<ForceCIPackaging>true</ForceCIPackaging>
<NoSignCI>true</NoSignCI>
</PropertyGroup>
<!-- Target to generate sparse MSIX package -->
<Target Name="GenerateSparsePackage" BeforeTargets="PrepareForBuild">
<!-- Use NoSign only for CI builds to avoid certificate issues on hosted agents -->
<PropertyGroup>
<NoSignParam Condition="'$(NoSignCI)' == 'true'">-NoSign</NoSignParam>
<NoSignParam Condition="'$(NoSignCI)' != 'true'"></NoSignParam>
<CIBuildParam Condition="'$(CIBuild)' == 'true'">-CIBuild</CIBuildParam>
<CIBuildParam Condition="'$(CIBuild)' != 'true'"></CIBuildParam>
</PropertyGroup>
<Exec Command="pwsh -NonInteractive -ExecutionPolicy Bypass -File &quot;$(MSBuildThisFileDirectory)BuildSparsePackage.ps1&quot; -Platform $(Platform) -Configuration $(Configuration) $(NoSignParam) $(CIBuildParam)"
ContinueOnError="false"
WorkingDirectory="$(MSBuildThisFileDirectory)" />
</Target>
<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>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{E2A5A82E-1E5B-4C8D-9A4F-2B1A8F9E5C3D}</ProjectGuid>
<RootNamespace>PackageIdentity</RootNamespace>
<ProjectName>PackageIdentity</ProjectName>
<UseFastUpToDateCheck>false</UseFastUpToDateCheck>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Utility</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Solution.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<None Include="AppxManifest.xml" />
<None Include="BuildSparsePackage.ps1" />
<None Include="BuildSparsePackage.cmd" />
<None Include="Check-ProcessIdentity.ps1" />
</ItemGroup>
<ItemGroup>
<Image Include="Images\Square150x150Logo.png">
<Filter>Images</Filter>
</Image>
<Image Include="Images\Square44x44Logo.png">
<Filter>Images</Filter>
</Image>
<Image Include="Images\StoreLogo.png">
<Filter>Images</Filter>
</Image>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Images">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>png;jpg;jpeg;gif;bmp;ico</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="AppxManifest.xml" />
<None Include="BuildSparsePackage.ps1" />
<None Include="BuildSparsePackage.cmd" />
</ItemGroup>
<ItemGroup>
<Image Include="Images\Square150x150Logo.png">
<Filter>Images</Filter>
</Image>
<Image Include="Images\Square44x44Logo.png">
<Filter>Images</Filter>
</Image>
<Image Include="Images\StoreLogo.png">
<Filter>Images</Filter>
</Image>
</ItemGroup>
</Project>

View File

@@ -1,90 +0,0 @@
# PowerToys sparse package identity
This document describes how to build, sign, register, and consume the shared sparse MSIX package that grants package identity to select Win32 components of PowerToys.
## Package overview
The sparse package lives under `src/PackageIdentity`. It produces a payload-free MSIX whose `Identity` matches `Microsoft.PowerToys.SparseApp`. The manifest contains one entry per Win32 surface that should run with identity (for example Settings, PowerOCR, Image Resizer).
> The MSIX contains only metadata. When the package is registered you must point `-ExternalLocation` to the output folder that hosts the Win32 binaries (for example `x64\Release`).
## Building the sparse package locally
Two options are available:
- Build the utility project from Visual Studio: `PackageIdentity.vcxproj` defines a `GenerateSparsePackage` target that runs before `PrepareForBuild` and invokes the helper script automatically.
- Invoke the helper script directly from PowerShell:
```powershell
$repoRoot = "C:/git/PowerToys"
pwsh "$repoRoot/src/PackageIdentity/BuildSparsePackage.ps1" -Platform x64 -Configuration Release
```
Supported switches:
- `-Clean` removes previous `bin`/`obj` outputs and uninstalls existing installation.
- `-ForceCert` regenerates the local dev certificate (.pfx/.cer/.pwd/.thumbprint) under `src/PackageIdentity/.user`.
- `-NoSign` skips signing. The MSIX still builds but must be signed before deployment.
- `-CIBuild` (or setting `$env:CIBuild = 'true'`) keeps the manifest publisher intact and skips the local cert substitution.
The script determines the proper `makeappx.exe` for the host build machine (x64 on typical developer boxes) and creates `PowerToysSparse.msix` in `{repo}\<Platform>\<Configuration>`.
> After packaging finishes, the helper also emits `src/PackageIdentity/.user/PowerToysSparse.publisher.txt`. This file mirrors the publisher string Windows will see once the sparse package is registered, which downstream projects can read to stay in sync when generating their own manifests.
## Local signing basics
When `-NoSign` is not used the script generates (or reuses) a development certificate and signs the package via `signtool.exe`:
1. Artifacts are stored in `src/PackageIdentity/.user/PowerToysSparse.certificate.sample.*` (`.cer` and `.thumbprint`).
2. Install the `.cer` into `CurrentUser``TrustedPeople` (and `TrustedRoot`, if necessary) so Windows trusts the signature:
```powershell
$repoRoot = "C:/git/PowerToys"
Import-Certificate -FilePath "$repoRoot/src/PackageIdentity/.user/PowerToysSparse.certificate.sample.cer" -CertStoreLocation Cert:\CurrentUser\TrustedPeople
```
3. The private key stays in the current user's personal certificate store.
## Registering or unregistering the package
After `PowerToysSparse.msix` is generated:
```powershell
# First time registration
$repoRoot = "C:/git/PowerToys"
$outputRoot = Join-Path $repoRoot "x64/Release"
Add-AppxPackage -Path (Join-Path $outputRoot "PowerToysSparse.msix") -ExternalLocation $outputRoot
# Re-register after manifest tweaks only
Add-AppxPackage -Register (Join-Path $repoRoot "src/PackageIdentity/AppxManifest.xml") -ExternalLocation $outputRoot -ForceApplicationShutdown
# Remove the sparse identity
Get-AppxPackage -Name Microsoft.PowerToys.SparseApp | Remove-AppxPackage
```
`-ExternalLocation` should match the output folder that contains the Win32 executables declared in the manifest. Re-run registration whenever the manifest or executable layout changes.
## CI-specific guidance
- Pass `-CIBuild` to `BuildSparsePackage.ps1` (or build with `msbuild PackageIdentity.vcxproj /p:CIBuild=true`). This prevents the script from rewriting the manifest publisher to the local dev certificate subject.
- The project automatically adds `-NoSign` only when `$(CIBuild)` is `true`. Local Debug and Release builds are signed with the development certificate.
- Make sure the agent trusts whichever certificate signs the package. If the package remains unsigned (`-NoSign`) it cannot be installed on test machines until it is signed.
## Consuming the identity from other components
1. Add a new `<Application>` entry inside `src/PackageIdentity/AppxManifest.xml`. Use a unique `Id` (for example `PowerToys.MyModuleUI`) and set `Executable` to the Win32 binary relative to the `-ExternalLocation` root.
2. Ensure the binary is copied into the platform/configuration output folder (`x64\Release`, `ARM64\Debug`, etc.) so the sparse package can locate it.
3. Embed a sparse identity manifest in the Win32 binary so it binds to the MSIX identity at runtime. The manifest must declare an `<msix>` element with `packageName="Microsoft.PowerToys.SparseApp"`, `applicationId` matching the `<Application Id>`, and a `publisher` that matches the sparse package. Keep the manifests publisher in sync with `src/PackageIdentity/.user/PowerToysSparse.publisher.txt` (emitted by `BuildSparsePackage.ps1`). See `src/modules/imageresizer/ui/ImageResizerUI.csproj` for an example that points `ApplicationManifest` to `ImageResizerUI.dev.manifest` for local builds and switches to `ImageResizerUI.prod.manifest` when `$(CIBuild)` is `true`.
4. Register or re-register the sparse package so Windows learns about the new application Id.
5. To launch the Win32 surface with identity, use the `shell:AppsFolder` activation form (for example: `shell:AppsFolder\Microsoft.PowerToys.SparseApp_<PackageFamilyName>!PowerToys.MyModuleUI`) or activate it via `IApplicationActivationManager::ActivateApplication` using the same AppUserModelID.
- For locally built packages, resolve the `<PackageFamilyName>` with `Get-AppxPackage -Name Microsoft.PowerToys.SparseApp | Select-Object -ExpandProperty PackageFamilyName`.
- Store-distributed builds use `Microsoft.PowerToys.SparseApp_8wekyb3d8bbwe`. Local developer builds created by this script typically use a different family name derived from the dev certificate.
6. Context menu handlers or other launchers should fall back to the unpackaged executable path for environments where the sparse package is not present.
## Troubleshooting tips
- `Program 'makeappx.exe' failed to run`: make sure you are running an x64 PowerShell host. The script now chooses the appropriate makeappx automatically; update your repo if the log still points to an ARM64 binary.
- `HRESULT 0x800B0109 (trust failure)`: install the development certificate into both `TrustedPeople` and `TrustedRoot` stores for the current user.
- Stale registration: remove the package with `Remove-AppxPackage` and re-run the script with `-Clean` to rebuild from scratch.

View File

@@ -112,10 +112,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredMousePointerCrosshairsEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredCursorWrapEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCursorWrapEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredPowerRenameEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredPowerRenameEnabledValue());
@@ -196,34 +192,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOnlineAIModelsValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteOpenAIValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOpenAIValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteAzureOpenAIValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteAzureOpenAIValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteAzureAIInferenceValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteAzureAIInferenceValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteMistralValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteMistralValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteGoogleValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteGoogleValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteOllamaValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOllamaValue());
}
GpoRuleConfigured GPOWrapper::GetAllowedAdvancedPasteFoundryLocalValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteFoundryLocalValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredNewPlusEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredNewPlusEnabledValue());

View File

@@ -35,7 +35,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
@@ -55,13 +54,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOnlineAIModelsValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureAIInferenceValue();
static GpoRuleConfigured GetAllowedAdvancedPasteMistralValue();
static GpoRuleConfigured GetAllowedAdvancedPasteGoogleValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOllamaValue();
static GpoRuleConfigured GetAllowedAdvancedPasteFoundryLocalValue();
static GpoRuleConfigured GetConfiguredNewPlusEnabledValue();
static GpoRuleConfigured GetConfiguredWorkspacesEnabledValue();
static GpoRuleConfigured GetConfiguredMwbClipboardSharingEnabledValue();

View File

@@ -38,7 +38,6 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
static GpoRuleConfigured GetConfiguredCursorWrapEnabledValue();
static GpoRuleConfigured GetConfiguredMouseWithoutBordersEnabledValue();
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
@@ -59,13 +58,6 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOnlineAIModelsValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureOpenAIValue();
static GpoRuleConfigured GetAllowedAdvancedPasteAzureAIInferenceValue();
static GpoRuleConfigured GetAllowedAdvancedPasteMistralValue();
static GpoRuleConfigured GetAllowedAdvancedPasteGoogleValue();
static GpoRuleConfigured GetAllowedAdvancedPasteOllamaValue();
static GpoRuleConfigured GetAllowedAdvancedPasteFoundryLocalValue();
static GpoRuleConfigured GetConfiguredNewPlusEnabledValue();
static GpoRuleConfigured GetConfiguredWorkspacesEnabledValue();
static GpoRuleConfigured GetConfiguredMwbClipboardSharingEnabledValue();

View File

@@ -1,7 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace LanguageModelProvider.FoundryLocal;
internal sealed record FoundryCachedModel(string Name, string? Id);

View File

@@ -1,61 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
internal sealed record FoundryCatalogModel
{
[JsonPropertyName("name")]
public string Name { get; init; } = string.Empty;
[JsonPropertyName("displayName")]
public string DisplayName { get; init; } = string.Empty;
[JsonPropertyName("providerType")]
public string ProviderType { get; init; } = string.Empty;
[JsonPropertyName("uri")]
public string Uri { get; init; } = string.Empty;
[JsonPropertyName("version")]
public string Version { get; init; } = string.Empty;
[JsonPropertyName("modelType")]
public string ModelType { get; init; } = string.Empty;
[JsonPropertyName("promptTemplate")]
public PromptTemplate PromptTemplate { get; init; } = default!;
[JsonPropertyName("publisher")]
public string Publisher { get; init; } = string.Empty;
[JsonPropertyName("task")]
public string Task { get; init; } = string.Empty;
[JsonPropertyName("runtime")]
public Runtime Runtime { get; init; } = default!;
[JsonPropertyName("fileSizeMb")]
public long FileSizeMb { get; init; }
[JsonPropertyName("modelSettings")]
public ModelSettings ModelSettings { get; init; } = default!;
[JsonPropertyName("alias")]
public string Alias { get; init; } = string.Empty;
[JsonPropertyName("supportsToolCalling")]
public bool SupportsToolCalling { get; init; }
[JsonPropertyName("license")]
public string License { get; init; } = string.Empty;
[JsonPropertyName("licenseDescription")]
public string LicenseDescription { get; init; } = string.Empty;
[JsonPropertyName("parentModelUri")]
public string ParentModelUri { get; init; } = string.Empty;
}

View File

@@ -1,279 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using ManagedCommon;
using Microsoft.AI.Foundry.Local;
namespace LanguageModelProvider.FoundryLocal;
internal sealed class FoundryClient
{
public static async Task<FoundryClient?> CreateAsync()
{
// First attempt with current environment
var client = await TryCreateClientAsync().ConfigureAwait(false);
if (client != null)
{
return client;
}
// If failed, refresh PATH from registry and retry once
// This handles cases where PowerToys was launched by MSI installer.
Logger.LogInfo("[FoundryClient] First attempt failed, refreshing PATH and retrying");
RefreshEnvironmentPath();
return await TryCreateClientAsync().ConfigureAwait(false);
}
private static async Task<FoundryClient?> TryCreateClientAsync()
{
try
{
Logger.LogInfo("[FoundryClient] Creating Foundry Local client");
var manager = new FoundryLocalManager();
// Check if service is already running
if (manager.IsServiceRunning)
{
Logger.LogInfo("[FoundryClient] Foundry service is already running");
return new FoundryClient(manager);
}
// Start the service using SDK's method
Logger.LogInfo("[FoundryClient] Starting Foundry service using manager.StartServiceAsync()");
await manager.StartServiceAsync().ConfigureAwait(false);
Logger.LogInfo("[FoundryClient] Foundry service started successfully");
return new FoundryClient(manager);
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Error creating client: {ex.Message}");
if (ex.InnerException != null)
{
Logger.LogError($"[FoundryClient] Inner exception: {ex.InnerException.Message}");
}
return null;
}
}
private readonly FoundryLocalManager _foundryManager;
private readonly List<FoundryCatalogModel> _catalogModels = [];
private FoundryClient(FoundryLocalManager foundryManager)
{
_foundryManager = foundryManager;
}
public Task<string?> GetServiceUrl()
{
try
{
return Task.FromResult(_foundryManager.Endpoint?.ToString());
}
catch
{
return Task.FromResult<string?>(null);
}
}
public Uri? GetServiceUri()
{
try
{
return _foundryManager.ServiceUri;
}
catch
{
return null;
}
}
public async Task<List<FoundryCatalogModel>> ListCatalogModels()
{
if (_catalogModels.Count > 0)
{
return _catalogModels;
}
try
{
Logger.LogInfo("[FoundryClient] Listing catalog models");
var models = await _foundryManager.ListCatalogModelsAsync().ConfigureAwait(false);
if (models != null)
{
foreach (var model in models)
{
_catalogModels.Add(new FoundryCatalogModel
{
Name = model.ModelId ?? string.Empty,
DisplayName = model.DisplayName ?? string.Empty,
ProviderType = model.ProviderType ?? string.Empty,
Uri = model.Uri ?? string.Empty,
Version = model.Version ?? string.Empty,
ModelType = model.ModelType ?? string.Empty,
Publisher = model.Publisher ?? string.Empty,
Task = model.Task ?? string.Empty,
FileSizeMb = model.FileSizeMb,
Alias = model.Alias ?? string.Empty,
License = model.License ?? string.Empty,
LicenseDescription = model.LicenseDescription ?? string.Empty,
ParentModelUri = model.ParentModelUri ?? string.Empty,
SupportsToolCalling = model.SupportsToolCalling,
});
}
Logger.LogInfo($"[FoundryClient] Found {_catalogModels.Count} catalog models");
}
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Error listing catalog models: {ex.Message}");
// Surfacing errors here prevents listing other providers; swallow and return cached list instead.
}
return _catalogModels;
}
public async Task<List<FoundryCachedModel>> ListCachedModels()
{
try
{
Logger.LogInfo("[FoundryClient] Listing cached models");
var cachedModels = await _foundryManager.ListCachedModelsAsync().ConfigureAwait(false);
var catalogModels = await ListCatalogModels().ConfigureAwait(false);
List<FoundryCachedModel> models = [];
foreach (var model in cachedModels)
{
var catalogModel = catalogModels.FirstOrDefault(m => m.Name == model.ModelId);
var alias = catalogModel?.Alias ?? model.Alias;
models.Add(new FoundryCachedModel(model.ModelId ?? string.Empty, alias));
}
Logger.LogInfo($"[FoundryClient] Found {models.Count} cached models");
return models;
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Error listing cached models: {ex.Message}");
return [];
}
}
public async Task<bool> IsModelLoaded(string modelId)
{
try
{
var loadedModels = await _foundryManager.ListLoadedModelsAsync().ConfigureAwait(false);
var isLoaded = loadedModels.Any(m => m.ModelId == modelId);
Logger.LogInfo($"[FoundryClient] IsModelLoaded({modelId}): {isLoaded}");
Logger.LogInfo($"[FoundryClient] Loaded models: {string.Join(", ", loadedModels.Select(m => m.ModelId))}");
return isLoaded;
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] IsModelLoaded exception: {ex.Message}");
return false;
}
}
public async Task<bool> EnsureModelLoaded(string modelId)
{
Logger.LogInfo($"[FoundryClient] EnsureModelLoaded called with: {modelId}");
// Check if already loaded
if (await IsModelLoaded(modelId).ConfigureAwait(false))
{
Logger.LogInfo($"[FoundryClient] Model already loaded: {modelId}");
return true;
}
// Load the model
Logger.LogInfo($"[FoundryClient] Loading model: {modelId}");
await _foundryManager.LoadModelAsync(modelId).ConfigureAwait(false);
// Verify it's loaded
var loaded = await IsModelLoaded(modelId).ConfigureAwait(false);
Logger.LogInfo($"[FoundryClient] Model load result: {loaded}");
return loaded;
}
public async Task EnsureRunning()
{
if (!_foundryManager.IsServiceRunning)
{
await _foundryManager.StartServiceAsync();
}
}
/// <summary>
/// Refreshes the PATH environment variable from the system registry.
/// This is necessary when tools are installed while PowerToys is running,
/// as the installer updates the system PATH but running processes don't see the change.
/// </summary>
private static void RefreshEnvironmentPath()
{
try
{
Logger.LogInfo("[FoundryClient] Refreshing PATH environment variable from system");
var currentPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) ?? string.Empty;
var machinePath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) ?? string.Empty;
var userPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User) ?? string.Empty;
var pathsToAdd = new List<string>();
if (!string.IsNullOrWhiteSpace(currentPath))
{
pathsToAdd.AddRange(currentPath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries));
}
if (!string.IsNullOrWhiteSpace(userPath))
{
var userPaths = userPath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries);
foreach (var path in userPaths)
{
if (!pathsToAdd.Contains(path, StringComparer.OrdinalIgnoreCase))
{
pathsToAdd.Add(path);
}
}
}
if (!string.IsNullOrWhiteSpace(machinePath))
{
var machinePaths = machinePath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries);
foreach (var path in machinePaths)
{
if (!pathsToAdd.Contains(path, StringComparer.OrdinalIgnoreCase))
{
pathsToAdd.Add(path);
}
}
}
var newPath = string.Join(Path.PathSeparator.ToString(), pathsToAdd);
if (currentPath != newPath)
{
Logger.LogInfo("[FoundryClient] Updating process PATH with latest system values");
Environment.SetEnvironmentVariable("PATH", newPath, EnvironmentVariableTarget.Process);
}
else
{
Logger.LogInfo("[FoundryClient] PATH is already up to date");
}
}
catch (Exception ex)
{
Logger.LogError($"[FoundryClient] Failed to refresh PATH: {ex.Message}");
}
}
}

View File

@@ -1,17 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
WriteIndented = false)]
[JsonSerializable(typeof(FoundryCatalogModel))]
[JsonSerializable(typeof(List<FoundryCatalogModel>))]
internal sealed partial class FoundryJsonContext : JsonSerializerContext
{
}

View File

@@ -1,16 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
internal sealed record ModelSettings
{
// The sample shows an empty array; keep it open-ended.
[JsonPropertyName("parameters")]
public List<JsonElement> Parameters { get; init; } = [];
}

View File

@@ -1,16 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
internal sealed record PromptTemplate
{
[JsonPropertyName("assistant")]
public string Assistant { get; init; } = string.Empty;
[JsonPropertyName("prompt")]
public string Prompt { get; init; } = string.Empty;
}

View File

@@ -1,16 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json.Serialization;
namespace LanguageModelProvider.FoundryLocal;
internal sealed record Runtime
{
[JsonPropertyName("deviceType")]
public string DeviceType { get; init; } = string.Empty;
[JsonPropertyName("executionProvider")]
public string ExecutionProvider { get; init; } = string.Empty;
}

View File

@@ -1,156 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ClientModel;
using LanguageModelProvider.FoundryLocal;
using ManagedCommon;
using Microsoft.Extensions.AI;
using OpenAI;
namespace LanguageModelProvider;
public sealed class FoundryLocalModelProvider : ILanguageModelProvider
{
private FoundryClient? _foundryClient;
private IEnumerable<FoundryCatalogModel>? _catalogModels;
private string? _serviceUrl;
public static FoundryLocalModelProvider Instance { get; } = new();
public string Name => "FoundryLocal";
public string ProviderDescription => "The model will run locally via Foundry Local";
public IChatClient? GetIChatClient(string modelId)
{
Logger.LogInfo($"[FoundryLocal] GetIChatClient called with url: {modelId}");
InitializeAsync().GetAwaiter().GetResult();
if (string.IsNullOrWhiteSpace(modelId))
{
Logger.LogError("[FoundryLocal] Model ID is empty after extraction");
return null;
}
// Check if model is in catalog
var isInCatalog = _catalogModels?.Any(m => m.Name == modelId) ?? false;
if (!isInCatalog)
{
var errorMessage = $"{modelId} is not supported in Foundry Local. Please configure supported models in Settings.";
Logger.LogError($"[FoundryLocal] {errorMessage}");
throw new InvalidOperationException(errorMessage);
}
// Ensure the model is loaded before returning chat client
var isLoaded = _foundryClient!.EnsureModelLoaded(modelId).GetAwaiter().GetResult();
if (!isLoaded)
{
Logger.LogError($"[FoundryLocal] Failed to load model: {modelId}");
throw new InvalidOperationException($"Failed to load the model '{modelId}'.");
}
// Use ServiceUri instead of Endpoint since Endpoint already includes /v1
var baseUri = _foundryClient.GetServiceUri();
if (baseUri == null)
{
const string message = "Foundry Local service URL is not available. Please make sure Foundry Local is installed and running.";
Logger.LogError($"[FoundryLocal] {message}");
throw new InvalidOperationException(message);
}
var endpointUri = new Uri($"{baseUri.ToString().TrimEnd('/')}/v1");
Logger.LogInfo($"[FoundryLocal] Creating OpenAI client with endpoint: {endpointUri}");
return new OpenAIClient(
new ApiKeyCredential("none"),
new OpenAIClientOptions { Endpoint = endpointUri, NetworkTimeout = TimeSpan.FromMinutes(5) })
.GetChatClient(modelId)
.AsIChatClient();
}
public string GetIChatClientString(string url)
{
try
{
InitializeAsync().GetAwaiter().GetResult();
}
catch
{
return string.Empty;
}
var modelId = url.Split('/').LastOrDefault();
if (string.IsNullOrWhiteSpace(_serviceUrl) || string.IsNullOrWhiteSpace(modelId))
{
return string.Empty;
}
return $"new OpenAIClient(new ApiKeyCredential(\"none\"), new OpenAIClientOptions{{ Endpoint = new Uri(\"{_serviceUrl}/v1\") }}).GetChatClient(\"{modelId}\").AsIChatClient()";
}
public async Task<IEnumerable<ModelDetails>> GetModelsAsync(CancellationToken cancelationToken = default)
{
await InitializeAsync(cancelationToken);
if (_foundryClient == null)
{
return Array.Empty<ModelDetails>();
}
var cachedModels = await _foundryClient.ListCachedModels();
List<ModelDetails> downloadedModels = [];
foreach (var model in cachedModels)
{
Logger.LogInfo($"[FoundryLocal] Adding unmatched cached model: {model.Name}");
downloadedModels.Add(new ModelDetails
{
Id = $"fl-{model.Name}",
Name = model.Name,
Url = $"fl://{model.Name}",
Description = $"{model.Name} running locally with Foundry Local",
HardwareAccelerators = [HardwareAccelerator.FOUNDRYLOCAL],
ProviderModelDetails = model,
});
}
return downloadedModels;
}
private async Task InitializeAsync(CancellationToken cancelationToken = default)
{
if (_foundryClient != null && _catalogModels != null && _catalogModels.Any())
{
await _foundryClient.EnsureRunning().ConfigureAwait(false);
return;
}
Logger.LogInfo("[FoundryLocal] Initializing provider");
_foundryClient ??= await FoundryClient.CreateAsync();
if (_foundryClient == null)
{
const string message = "Foundry Local client could not be created. Please make sure Foundry Local is installed and running.";
Logger.LogError($"[FoundryLocal] {message}");
throw new InvalidOperationException(message);
}
_serviceUrl ??= await _foundryClient.GetServiceUrl();
Logger.LogInfo($"[FoundryLocal] Service URL: {_serviceUrl}");
var catalogModels = await _foundryClient.ListCatalogModels();
Logger.LogInfo($"[FoundryLocal] Found {catalogModels.Count} catalog models");
_catalogModels = catalogModels;
}
public async Task<bool> IsAvailable()
{
Logger.LogInfo("[FoundryLocal] Checking availability");
await InitializeAsync();
var available = _foundryClient != null;
Logger.LogInfo($"[FoundryLocal] Available: {available}");
return available;
}
}

View File

@@ -1,22 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace LanguageModelProvider;
public enum HardwareAccelerator
{
CPU,
DML,
QNN,
WCRAPI,
OLLAMA,
OPENAI,
FOUNDRYLOCAL,
LEMONADE,
NPU,
GPU,
VitisAI,
OpenVINO,
NvTensorRT,
}

View File

@@ -1,20 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.AI;
namespace LanguageModelProvider;
public interface ILanguageModelProvider
{
string Name { get; }
string ProviderDescription { get; }
Task<IEnumerable<ModelDetails>> GetModelsAsync(CancellationToken cancelationToken = default);
IChatClient? GetIChatClient(string modelId);
string GetIChatClientString(string url);
}

View File

@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
<PackageReference Include="Microsoft.AI.Foundry.Local" />
<PackageReference Include="OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ManagedCommon\ManagedCommon.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,30 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace LanguageModelProvider;
public class ModelDetails
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public long Size { get; set; }
public bool IsUserAdded { get; set; }
public string Icon { get; set; } = string.Empty;
public List<HardwareAccelerator> HardwareAccelerators { get; set; } = [];
public string License { get; set; } = string.Empty;
public object? ProviderModelDetails { get; set; }
}

View File

@@ -26,21 +26,6 @@ namespace ManagedCommon
private static readonly string Version = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? "Unknown";
/// <summary>
/// Gets the path to the log directory for the current version of the app.
/// </summary>
public static string CurrentVersionLogDirectoryPath { get; private set; }
/// <summary>
/// Gets the path to the current log file.
/// </summary>
public static string CurrentLogFile { get; private set; }
/// <summary>
/// Gets the path to the log directory for the app.
/// </summary>
public static string AppLogDirectoryPath { get; private set; }
/// <summary>
/// Initializes the logger and sets the path for logging.
/// </summary>
@@ -57,12 +42,7 @@ namespace ManagedCommon
Directory.CreateDirectory(versionedPath);
}
AppLogDirectoryPath = basePath;
CurrentVersionLogDirectoryPath = versionedPath;
var logFile = "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log";
var logFilePath = Path.Combine(versionedPath, logFile);
CurrentLogFile = logFilePath;
var logFilePath = Path.Combine(versionedPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));
@@ -150,7 +130,7 @@ namespace ManagedCommon
{
exMessage +=
"Inner exception: " + Environment.NewLine +
ex.InnerException.GetType() + " (" + ex.InnerException.HResult + "): " + ex.InnerException.Message + Environment.NewLine;
ex.InnerException.GetType() + " (" + ex.HResult + "): " + ex.InnerException.Message + Environment.NewLine;
}
exMessage +=

View File

@@ -12,7 +12,6 @@ namespace ManagedCommon
ColorPicker,
CmdPal,
CropAndLock,
CursorWrap,
EnvironmentVariables,
FancyZones,
FileLocksmith,

View File

@@ -1,175 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.Json;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Helper class for configuring PowerToys settings for UI tests.
/// </summary>
public class SettingsConfigHelper
{
private static readonly JsonSerializerOptions IndentedJsonOptions = new() { WriteIndented = true };
private static readonly SettingsUtils SettingsUtils = new SettingsUtils();
/// <summary>
/// Configures global PowerToys settings to enable only specified modules and disable all others.
/// </summary>
/// <param name="modulesToEnable">Array of module names to enable (e.g., "Peek", "FancyZones"). All other modules will be disabled.</param>
/// <exception cref="ArgumentNullException">Thrown when modulesToEnable is null.</exception>
/// <exception cref="InvalidOperationException">Thrown when settings file operations fail.</exception>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is test code and will not be trimmed")]
[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "This is test code and will not be AOT compiled")]
public static void ConfigureGlobalModuleSettings(params string[] modulesToEnable)
{
ArgumentNullException.ThrowIfNull(modulesToEnable);
try
{
GeneralSettings settings;
try
{
settings = SettingsUtils.GetSettingsOrDefault<GeneralSettings>();
}
catch (Exception ex)
{
Debug.WriteLine($"Failed to load settings, creating defaults: {ex.Message}");
settings = new GeneralSettings();
}
string settingsJson = settings.ToJsonString();
using (JsonDocument doc = JsonDocument.Parse(settingsJson))
{
var options = new JsonSerializerOptions { WriteIndented = true };
var root = doc.RootElement.Clone();
if (root.TryGetProperty("enabled", out var enabledElement))
{
var enabledModules = new Dictionary<string, bool>();
foreach (var property in enabledElement.EnumerateObject())
{
string moduleName = property.Name;
bool shouldEnable = Array.Exists(modulesToEnable, m => string.Equals(m, moduleName, StringComparison.Ordinal));
enabledModules[moduleName] = shouldEnable;
}
var settingsDict = JsonSerializer.Deserialize<Dictionary<string, object>>(settingsJson);
if (settingsDict != null)
{
settingsDict["enabled"] = enabledModules;
settingsJson = JsonSerializer.Serialize(settingsDict, IndentedJsonOptions);
}
}
}
SettingsUtils.SaveSettings(settingsJson);
string enabledList = modulesToEnable.Length > 0 ? string.Join(", ", modulesToEnable) : "none";
Debug.WriteLine($"Successfully updated global settings");
Debug.WriteLine($"Enabled modules: {enabledList}");
}
catch (Exception ex)
{
Debug.WriteLine($"ERROR in ConfigureGlobalModuleSettings: {ex.Message}");
throw new InvalidOperationException($"Failed to configure global module settings: {ex.Message}", ex);
}
}
/// <summary>
/// Updates a module's settings file. If the file doesn't exist, creates it with default content.
/// If the file exists, reads it and applies the provided update function to modify the settings.
/// </summary>
/// <param name="moduleName">The name of the module (e.g., "Peek", "FancyZones").</param>
/// <param name="defaultSettingsContent">The default JSON content to use if the settings file doesn't exist.</param>
/// <param name="updateSettingsAction">
/// A callback function that modifies the settings dictionary. The function receives the deserialized settings
/// and should modify it in-place. The function should accept a Dictionary&lt;string, object&gt; and not return a value.
/// Example: (settings) => { ((Dictionary&lt;string, object&gt;)settings["properties"])["SomeSetting"] = newValue; }
/// </param>
/// <exception cref="ArgumentNullException">Thrown when moduleName or updateSettingsAction is null.</exception>
/// <exception cref="InvalidOperationException">Thrown when settings file operations fail.</exception>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "This is test code and will not be trimmed")]
[UnconditionalSuppressMessage("AOT", "IL3050", Justification = "This is test code and will not be AOT compiled")]
public static void UpdateModuleSettings(
string moduleName,
string defaultSettingsContent,
Action<Dictionary<string, object>> updateSettingsAction)
{
ArgumentNullException.ThrowIfNull(moduleName);
ArgumentNullException.ThrowIfNull(updateSettingsAction);
try
{
// Build the path to the module settings file
string powerToysSettingsDirectory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft",
"PowerToys");
string moduleDirectory = Path.Combine(powerToysSettingsDirectory, moduleName);
string settingsPath = Path.Combine(moduleDirectory, "settings.json");
// Ensure directory exists
Directory.CreateDirectory(moduleDirectory);
// Read existing settings or use default
string existingJson = string.Empty;
if (File.Exists(settingsPath))
{
existingJson = File.ReadAllText(settingsPath);
}
Dictionary<string, object>? settings;
// If file doesn't exist or is empty, create from defaults
if (string.IsNullOrWhiteSpace(existingJson))
{
if (string.IsNullOrWhiteSpace(defaultSettingsContent))
{
throw new ArgumentException("Default settings content must be provided when file doesn't exist.", nameof(defaultSettingsContent));
}
settings = JsonSerializer.Deserialize<Dictionary<string, object>>(defaultSettingsContent)
?? throw new InvalidOperationException($"Failed to deserialize default settings for {moduleName}");
Debug.WriteLine($"Created default settings for {moduleName} at {settingsPath}");
}
else
{
// Parse existing settings
settings = JsonSerializer.Deserialize<Dictionary<string, object>>(existingJson)
?? throw new InvalidOperationException($"Failed to deserialize existing settings for {moduleName}");
Debug.WriteLine($"Loaded existing settings for {moduleName} from {settingsPath}");
}
// Apply the update action to modify settings
updateSettingsAction(settings);
// Serialize and save the updated settings using SettingsUtils
string updatedJson = JsonSerializer.Serialize(settings, IndentedJsonOptions);
SettingsUtils.SaveSettings(updatedJson, moduleName);
Debug.WriteLine($"Successfully updated settings for {moduleName}");
}
catch (Exception ex)
{
Debug.WriteLine($"ERROR in UpdateModuleSettings for {moduleName}: {ex.Message}");
throw new InvalidOperationException($"Failed to update settings for {moduleName}: {ex.Message}", ex);
}
}
}
}

View File

@@ -8,7 +8,7 @@
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
<TargetFramework>net9.0-windows10.0.22621.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<PublishTrimmed>false</PublishTrimmed>
</PropertyGroup>
@@ -21,8 +21,4 @@
<PackageReference Include="CoenM.ImageSharp.ImageHash" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
</ItemGroup>
</Project>

View File

@@ -59,7 +59,6 @@ struct LogSettings
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
inline const static std::string mouseJumpLoggerName = "mouse-jump";
inline const static std::string mousePointerCrosshairsLoggerName = "mouse-pointer-crosshairs";
inline const static std::string cursorWrapLoggerName = "cursor-wrap";
inline const static std::string imageResizerLoggerName = "imageresizer";
inline const static std::string powerRenameLoggerName = "powerrename";
inline const static std::string alwaysOnTopLoggerName = "always-on-top";

View File

@@ -3,7 +3,6 @@
#include <Windows.h>
#include <optional>
#include <vector>
#include <string>
namespace powertoys_gpo
{
@@ -52,7 +51,6 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_HIGHLIGHTER = L"ConfigureEnabledUtilityMouseHighlighter";
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_JUMP = L"ConfigureEnabledUtilityMouseJump";
const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS = L"ConfigureEnabledUtilityMousePointerCrosshairs";
const std::wstring POLICY_CONFIGURE_ENABLED_CURSOR_WRAP = L"ConfigureEnabledUtilityCursorWrap";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_RENAME = L"ConfigureEnabledUtilityPowerRename";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER = L"ConfigureEnabledUtilityPowerLauncher";
const std::wstring POLICY_CONFIGURE_ENABLED_QUICK_ACCENT = L"ConfigureEnabledUtilityQuickAccent";
@@ -84,13 +82,6 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_RUN_AT_STARTUP = L"ConfigureRunAtStartup";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_LAUNCHER_ALL_PLUGINS = L"PowerLauncherAllPluginsEnabledState";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_ONLINE_AI_MODELS = L"AllowPowerToysAdvancedPasteOnlineAIModels";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_OPENAI = L"AllowAdvancedPasteOpenAI";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_AZURE_OPENAI = L"AllowAdvancedPasteAzureOpenAI";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_AZURE_AI_INFERENCE = L"AllowAdvancedPasteAzureAIInference";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_MISTRAL = L"AllowAdvancedPasteMistral";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_GOOGLE = L"AllowAdvancedPasteGoogle";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_OLLAMA = L"AllowAdvancedPasteOllama";
const std::wstring POLICY_ALLOW_ADVANCED_PASTE_FOUNDRY_LOCAL = L"AllowAdvancedPasteFoundryLocal";
const std::wstring POLICY_MWB_CLIPBOARD_SHARING_ENABLED = L"MwbClipboardSharingEnabled";
const std::wstring POLICY_MWB_FILE_TRANSFER_ENABLED = L"MwbFileTransferEnabled";
const std::wstring POLICY_MWB_USE_ORIGINAL_USER_INTERFACE = L"MwbUseOriginalUserInterface";
@@ -410,11 +401,6 @@ namespace powertoys_gpo
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_MOUSE_POINTER_CROSSHAIRS);
}
inline gpo_rule_configured_t getConfiguredCursorWrapEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CURSOR_WRAP);
}
inline gpo_rule_configured_t getConfiguredPowerRenameEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_POWER_RENAME);
@@ -589,41 +575,6 @@ namespace powertoys_gpo
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_ONLINE_AI_MODELS);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteOpenAIValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_OPENAI);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteAzureOpenAIValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_AZURE_OPENAI);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteAzureAIInferenceValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_AZURE_AI_INFERENCE);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteMistralValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_MISTRAL);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteGoogleValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_GOOGLE);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteOllamaValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_OLLAMA);
}
inline gpo_rule_configured_t getAllowedAdvancedPasteFoundryLocalValue()
{
return getConfiguredValue(POLICY_ALLOW_ADVANCED_PASTE_FOUNDRY_LOCAL);
}
inline gpo_rule_configured_t getConfiguredMwbClipboardSharingEnabledValue()
{
return getConfiguredValue(POLICY_MWB_CLIPBOARD_SHARING_ENABLED);

View File

@@ -33,4 +33,9 @@
<Target Name="PostBuildAction" AfterTargets="Build" Outputs="$(GeneratedDSCModule)" Condition="'$(Platform)'!='ARM64'">
<Exec Command="&quot;$(OutDir)$(AssemblyName).exe&quot; &quot;..\..\..\x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll&quot; $(GeneratedDSCModule) $(GeneratedDSCManifest)" />
</Target>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition="'$(Platform)'=='ARM64'">
<Exec Command="&quot;$(MSBuildToolsPath)\msbuild.exe&quot; PowerToys.sln -p:Configuration=&quot;$(Configuration)&quot; -p:Platform=&quot;x64&quot; -verbosity:m -t:DSC\PowerToys_Settings_DSC_Schema_Generator" WorkingDirectory="..\..\..\" />
</Target>
</Project>

View File

@@ -23,8 +23,7 @@ public sealed class SettingsResourceAdvancedPasteModuleTest : SettingsResourceMo
{
s.Properties.ShowCustomPreview = !s.Properties.ShowCustomPreview;
s.Properties.CloseAfterLosingFocus = !s.Properties.CloseAfterLosingFocus;
// s.Properties.IsAdvancedAIEnabled = !s.Properties.IsAdvancedAIEnabled;
s.Properties.IsAdvancedAIEnabled = !s.Properties.IsAdvancedAIEnabled;
s.Properties.AdvancedPasteUIShortcut = new HotkeySettings
{
Key = "mock",

View File

@@ -13,7 +13,7 @@ namespace PowerToys.DSC.Models;
public sealed class DscManifest
{
private const string Schema = "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.vscode.json";
private const string Executable = @"..\PowerToys.DSC.exe";
private const string Executable = @"PowerToys.DSC.exe";
private readonly string _type;
private readonly string _version;

View File

@@ -40,11 +40,9 @@
</EmbeddedResource>
</ItemGroup>
<!-- Generate the DSC resource JSON files to DSCModules subfolder -->
<!-- Skip generation in CI/CD builds (CIBuild=true) to avoid unnecessary work during pipeline -->
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(CIBuild)' != 'true'">
<Message Text="Generating DSC resource JSON files to DSCModules subfolder..." Importance="high" />
<MakeDir Directories="$(TargetDir)DSCModules" />
<Exec Command="dotnet &quot;$(TargetPath)&quot; manifest --resource settings --outputDir &quot;$(TargetDir)DSCModules&quot;" />
<!-- In debug mode, generate the DSC resource JSON files -->
<Target Name="GenerateDscResourceJsonFiles" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<Message Text="Generating DSC resource JSON files inside ..." Importance="high" />
<Exec Command="dotnet &quot;$(TargetPath)&quot; manifest --resource settings --outputDir &quot;$(TargetDir)\&quot;" />
</Target>
</Project>

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.18" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.17" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyNamespaces>
<target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" />
</policyNamespaces>
<resources minRequiredRevision="1.18"/><!-- Last changed with PowerToys v0.96.0 -->
<resources minRequiredRevision="1.17"/><!-- Last changed with PowerToys v0.90.0 -->
<supportedOn>
<definitions>
<definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/>
@@ -26,7 +26,6 @@
<definition name="SUPPORTED_POWERTOYS_0_88_0" displayName="$(string.SUPPORTED_POWERTOYS_0_88_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_89_0" displayName="$(string.SUPPORTED_POWERTOYS_0_89_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_90_0" displayName="$(string.SUPPORTED_POWERTOYS_0_90_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_96_0" displayName="$(string.SUPPORTED_POWERTOYS_0_96_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1)"/>
</definitions>
</supportedOn>
@@ -615,86 +614,6 @@
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteOpenAI" class="Both" displayName="$(string.AllowAdvancedPasteOpenAI)" explainText="$(string.AllowAdvancedPasteOpenAIDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteOpenAI">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAzureOpenAI" class="Both" displayName="$(string.AllowAdvancedPasteAzureOpenAI)" explainText="$(string.AllowAdvancedPasteAzureOpenAIDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAzureOpenAI">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAzureAIInference" class="Both" displayName="$(string.AllowAdvancedPasteAzureAIInference)" explainText="$(string.AllowAdvancedPasteAzureAIInferenceDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAzureAIInference">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteMistral" class="Both" displayName="$(string.AllowAdvancedPasteMistral)" explainText="$(string.AllowAdvancedPasteMistralDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteMistral">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteGoogle" class="Both" displayName="$(string.AllowAdvancedPasteGoogle)" explainText="$(string.AllowAdvancedPasteGoogleDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteGoogle">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteAnthropic" class="Both" displayName="$(string.AllowAdvancedPasteAnthropic)" explainText="$(string.AllowAdvancedPasteAnthropicDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteAnthropic">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteOllama" class="Both" displayName="$(string.AllowAdvancedPasteOllama)" explainText="$(string.AllowAdvancedPasteOllamaDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteOllama">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="AllowAdvancedPasteFoundryLocal" class="Both" displayName="$(string.AllowAdvancedPasteFoundryLocal)" explainText="$(string.AllowAdvancedPasteFoundryLocalDescription)" key="Software\Policies\PowerToys" valueName="AllowAdvancedPasteFoundryLocal">
<parentCategory ref="AdvancedPaste" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_96_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
<policy name="MwbClipboardSharingEnabled" class="Both" displayName="$(string.MwbClipboardSharingEnabled)" explainText="$(string.MwbClipboardSharingEnabledDescription)" key="Software\Policies\PowerToys" valueName="MwbClipboardSharingEnabled">
<parentCategory ref="MouseWithoutBorders" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_83_0" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.18" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.17" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<displayName>PowerToys</displayName>
<description>PowerToys</description>
<resources>
@@ -33,7 +33,6 @@
<string id="SUPPORTED_POWERTOYS_0_88_0">PowerToys version 0.88.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_89_0">PowerToys version 0.89.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_90_0">PowerToys version 0.90.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_96_0">PowerToys version 0.96.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1">From PowerToys version 0.64.0 until PowerToys version 0.87.1</string>
<string id="ConfigureAllUtilityGlobalEnabledStateDescription">This policy configures the enabled state for all PowerToys utilities.
@@ -292,54 +291,6 @@ If you don't configure this policy, the user will be able to control the setting
<string id="ConfigureEnabledUtilityFileExplorerQOIPreview">QOI file preview: Configure enabled state</string>
<string id="ConfigureEnabledUtilityFileExplorerQOIThumbnails">QOI file thumbnail: Configure enabled state</string>
<string id="AllowPowerToysAdvancedPasteOnlineAIModels">Allow using online AI models</string>
<string id="AllowAdvancedPasteOpenAI">Advanced Paste: Allow OpenAI endpoint</string>
<string id="AllowAdvancedPasteOpenAIDescription">This policy controls whether users can use the OpenAI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use OpenAI as their AI provider.
If you disable this policy, users will not be able to select or use OpenAI endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAzureOpenAI">Advanced Paste: Allow Azure OpenAI endpoint</string>
<string id="AllowAdvancedPasteAzureOpenAIDescription">This policy controls whether users can use the Azure OpenAI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Azure OpenAI as their AI provider.
If you disable this policy, users will not be able to select or use Azure OpenAI endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAzureAIInference">Advanced Paste: Allow Azure AI Inference endpoint</string>
<string id="AllowAdvancedPasteAzureAIInferenceDescription">This policy controls whether users can use the Azure AI Inference endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Azure AI Inference as their AI provider.
If you disable this policy, users will not be able to select or use Azure AI Inference endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteMistral">Advanced Paste: Allow Mistral endpoint</string>
<string id="AllowAdvancedPasteMistralDescription">This policy controls whether users can use the Mistral AI endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Mistral as their AI provider.
If you disable this policy, users will not be able to select or use Mistral endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteGoogle">Advanced Paste: Allow Google endpoint</string>
<string id="AllowAdvancedPasteGoogleDescription">This policy controls whether users can use the Google (Gemini) endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Google as their AI provider.
If you disable this policy, users will not be able to select or use Google endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteAnthropic">Advanced Paste: Allow Anthropic endpoint</string>
<string id="AllowAdvancedPasteAnthropicDescription">This policy controls whether users can use the Anthropic (Claude) endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Anthropic as their AI provider.
If you disable this policy, users will not be able to select or use Anthropic endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteOllama">Advanced Paste: Allow Ollama endpoint</string>
<string id="AllowAdvancedPasteOllamaDescription">This policy controls whether users can use the Ollama local model endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Ollama as their AI provider.
If you disable this policy, users will not be able to select or use Ollama endpoint in Advanced Paste settings.</string>
<string id="AllowAdvancedPasteFoundryLocal">Advanced Paste: Allow Foundry Local endpoint</string>
<string id="AllowAdvancedPasteFoundryLocalDescription">This policy controls whether users can use the Foundry Local model endpoint in Advanced Paste.
If you enable or don't configure this policy, users can configure and use Foundry Local as their AI provider.
If you disable this policy, users will not be able to select or use Foundry Local endpoint in Advanced Paste settings.</string>
<string id="MwbClipboardSharingEnabled">Clipboard sharing enabled</string>
<string id="MwbFileTransferEnabled">File transfer enabled</string>
<string id="MwbUseOriginalUserInterface">Original user interface is available</string>

View File

@@ -1,68 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using AdvancedPaste.Models;
using AdvancedPaste.Settings;
using Microsoft.PowerToys.Settings.UI.Library;
namespace AdvancedPaste.UnitTests.Mocks;
/// <summary>
/// Minimal <see cref="IUserSettings"/> implementation used by integration tests that
/// need to construct the runtime Advanced Paste services.
/// </summary>
internal sealed class IntegrationTestUserSettings : IUserSettings
{
private readonly PasteAIConfiguration _configuration;
private readonly IReadOnlyList<AdvancedPasteCustomAction> _customActions;
private readonly IReadOnlyList<PasteFormats> _additionalActions;
public IntegrationTestUserSettings()
{
var provider = new PasteAIProviderDefinition
{
Id = "integration-openai",
EnableAdvancedAI = true,
ServiceTypeKind = AIServiceType.OpenAI,
ModelName = "gpt-4o",
ModerationEnabled = true,
};
_configuration = new PasteAIConfiguration
{
ActiveProviderId = provider.Id,
Providers = new ObservableCollection<PasteAIProviderDefinition> { provider },
};
_customActions = Array.Empty<AdvancedPasteCustomAction>();
_additionalActions = Array.Empty<PasteFormats>();
}
public bool IsAIEnabled => true;
public bool ShowCustomPreview => false;
public bool CloseAfterLosingFocus => false;
public bool EnableClipboardPreview => true;
public IReadOnlyList<AdvancedPasteCustomAction> CustomActions => _customActions;
public IReadOnlyList<PasteFormats> AdditionalActions => _additionalActions;
public PasteAIConfiguration PasteAIConfiguration => _configuration;
public event EventHandler Changed;
public Task SetActiveAIProviderAsync(string providerId)
{
_configuration.ActiveProviderId = providerId ?? string.Empty;
Changed?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask;
}
}

View File

@@ -13,8 +13,6 @@ using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Services.OpenAI;
using AdvancedPaste.UnitTests.Mocks;
using ManagedCommon;
@@ -81,9 +79,7 @@ public sealed class AIServiceBatchIntegrationTests
Assert.IsTrue(results.Count <= inputs.Count);
CollectionAssert.AreEqual(results.Select(result => result.ToInput()).ToList(), inputs.Take(results.Count).ToList());
#pragma warning disable IL2026, IL3050 // The tests rely on runtime JSON serialization for ad-hoc data files.
async Task WriteResultsAsync() => await File.WriteAllTextAsync(resultsFile, JsonSerializer.Serialize(results, SerializerOptions));
#pragma warning restore IL2026, IL3050
Logger.LogInfo($"Starting {nameof(TestGenerateBatchResults)}; Count={inputs.Count}, InCache={results.Count}");
@@ -105,12 +101,8 @@ public sealed class AIServiceBatchIntegrationTests
await WriteResultsAsync();
}
private static async Task<List<T>> GetDataListAsync<T>(string filePath)
{
#pragma warning disable IL2026, IL3050 // Tests only run locally and can depend on runtime JSON serialization.
return File.Exists(filePath) ? JsonSerializer.Deserialize<List<T>>(await File.ReadAllTextAsync(filePath)) : [];
#pragma warning restore IL2026, IL3050
}
private static async Task<List<T>> GetDataListAsync<T>(string filePath) =>
File.Exists(filePath) ? JsonSerializer.Deserialize<List<T>>(await File.ReadAllTextAsync(filePath)) : [];
private static async Task<string> GetTextOutputAsync(BatchTestInput input, PasteFormats format)
{
@@ -138,35 +130,23 @@ public sealed class AIServiceBatchIntegrationTests
private static async Task<DataPackage> GetOutputDataPackageAsync(BatchTestInput batchTestInput, PasteFormats format)
{
var services = CreateServices();
VaultCredentialsProvider credentialsProvider = new();
PromptModerationService promptModerationService = new(credentialsProvider);
NoOpProgress progress = new();
CustomTextTransformService customTextTransformService = new(credentialsProvider, promptModerationService);
switch (format)
{
case PasteFormats.CustomTextTransformation:
var transformResult = await services.CustomActionTransformService.TransformAsync(batchTestInput.Prompt, batchTestInput.Clipboard, null, CancellationToken.None, progress);
return DataPackageHelpers.CreateFromText(transformResult.Content ?? string.Empty);
return DataPackageHelpers.CreateFromText(await customTextTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress));
case PasteFormats.KernelQuery:
var clipboardData = DataPackageHelpers.CreateFromText(batchTestInput.Clipboard).GetView();
return await services.KernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false, CancellationToken.None, progress);
KernelService kernelService = new(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, customTextTransformService);
return await kernelService.TransformClipboardAsync(batchTestInput.Prompt, clipboardData, isSavedQuery: false, CancellationToken.None, progress);
default:
throw new InvalidOperationException($"Unexpected format {format}");
}
}
private static IntegrationTestServices CreateServices()
{
IntegrationTestUserSettings userSettings = new();
EnhancedVaultCredentialsProvider credentialsProvider = new(userSettings);
PromptModerationService promptModerationService = new(credentialsProvider);
PasteAIProviderFactory providerFactory = new();
ICustomActionTransformService customActionTransformService = new CustomActionTransformService(promptModerationService, providerFactory, credentialsProvider, userSettings);
IKernelService kernelService = new AdvancedAIKernelService(credentialsProvider, new NoOpKernelQueryCacheService(), promptModerationService, userSettings, customActionTransformService);
return new IntegrationTestServices(customActionTransformService, kernelService);
}
private readonly record struct IntegrationTestServices(ICustomActionTransformService CustomActionTransformService, IKernelService KernelService);
}

View File

@@ -11,8 +11,6 @@ using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Services.OpenAI;
using AdvancedPaste.Telemetry;
using AdvancedPaste.UnitTests.Mocks;
@@ -29,19 +27,16 @@ namespace AdvancedPaste.UnitTests.ServicesTests;
public sealed class KernelServiceIntegrationTests : IDisposable
{
private const string StandardImageFile = "image_with_text_example.png";
private IKernelService _kernelService;
private KernelService _kernelService;
private AdvancedPasteEventListener _eventListener;
[TestInitialize]
public void TestInitialize()
{
IntegrationTestUserSettings userSettings = new();
EnhancedVaultCredentialsProvider credentialsProvider = new(userSettings);
VaultCredentialsProvider credentialsProvider = new();
PromptModerationService promptModerationService = new(credentialsProvider);
PasteAIProviderFactory providerFactory = new();
CustomActionTransformService customActionTransformService = new(promptModerationService, providerFactory, credentialsProvider, userSettings);
_kernelService = new AdvancedAIKernelService(credentialsProvider, new NoOpKernelQueryCacheService(), promptModerationService, userSettings, customActionTransformService);
_kernelService = new KernelService(new NoOpKernelQueryCacheService(), credentialsProvider, promptModerationService, new CustomTextTransformService(credentialsProvider, promptModerationService));
_eventListener = new();
}

View File

@@ -33,14 +33,11 @@
</PropertyGroup>
<ItemGroup>
<None Remove="AdvancedPasteXAML\Controls\ClipboardHistoryItemPreviewControl.xaml" />
<None Remove="AdvancedPasteXAML\Controls\PromptBox.xaml" />
<None Remove="AdvancedPasteXAML\Styles\Button.xaml" />
<None Remove="Assets\AdvancedPaste\AIIcon.png" />
<None Remove="Assets\AdvancedPaste\Gradient.png" />
<None Remove="AdvancedPasteXAML\Controls\AnimatedContentControl\AnimatedBorderBrush.xaml" />
<None Remove="AdvancedPasteXAML\Views\MainPage.xaml" />
<None Remove="Assets\AdvancedPaste\SemanticKernel.svg" />
</ItemGroup>
<ItemGroup>
@@ -52,6 +49,7 @@
<ItemGroup>
<PackageReference Include="OpenAI" />
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="CommunityToolkit.WinUI.Animations" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
@@ -59,15 +57,10 @@
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
<PackageReference Include="MessagePack" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAIInference" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.MistralAI" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Ollama" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.SemanticKernel" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<PackageReference Include="System.ClientModel" />
<PackageReference Include="Microsoft.Windows.Compatibility" />
<PackageReference Include="Microsoft.Windows.CsWin32" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
@@ -109,7 +102,6 @@
<!-- HACK: Common.UI is referenced, even if it is not used, to force dll versions to be the same as in other projects that use it. It's still unclear why this is the case, but this is need for flattening the install directory. -->
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\common\LanguageModelProvider\LanguageModelProvider.csproj" />
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
</ItemGroup>
@@ -122,38 +114,9 @@
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
<ItemGroup>
<Page Update="AdvancedPasteXAML\Controls\ClipboardHistoryItemPreviewControl.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="AdvancedPasteXAML\Controls\PromptBox.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="AdvancedPasteXAML\Styles\Button.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<!-- Share AI Model Provider Icons from Settings.UI to avoid duplication -->
<!-- These icons are included from Settings.UI project -->
<Content Include="..\..\..\settings-ui\Settings.UI\Assets\Settings\Icons\Models\*.svg">
<Link>Assets\Settings\Icons\Models\%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<!-- AdvancedPaste specific assets -->
<Content Include="Assets\AdvancedPaste\*.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\AdvancedPaste\*.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<!-- Keep SemanticKernel.svg as it's specific to AdvancedPaste -->
<Content Include="Assets\AdvancedPaste\SemanticKernel.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -9,7 +9,6 @@
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<ResourceDictionary Source="ms-appx:///AdvancedPasteXAML/Controls/AnimatedContentControl/AnimatedContentControl.xaml" />
<ResourceDictionary Source="ms-appx:///AdvancedPasteXAML/Styles/Button.xaml" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->

View File

@@ -10,10 +10,10 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using AdvancedPaste.Services;
using AdvancedPaste.Services.CustomActions;
using AdvancedPaste.Settings;
using AdvancedPaste.ViewModels;
using ManagedCommon;
@@ -77,12 +77,11 @@ namespace AdvancedPaste
{
services.AddSingleton<IFileSystem, FileSystem>();
services.AddSingleton<IUserSettings, UserSettings>();
services.AddSingleton<IAICredentialsProvider, EnhancedVaultCredentialsProvider>();
services.AddSingleton<IAICredentialsProvider, Services.OpenAI.VaultCredentialsProvider>();
services.AddSingleton<IPromptModerationService, Services.OpenAI.PromptModerationService>();
services.AddSingleton<ICustomTextTransformService, Services.OpenAI.CustomTextTransformService>();
services.AddSingleton<IKernelQueryCacheService, CustomActionKernelQueryCacheService>();
services.AddSingleton<IPasteAIProviderFactory, PasteAIProviderFactory>();
services.AddSingleton<ICustomActionTransformService, CustomActionTransformService>();
services.AddSingleton<IKernelService, AdvancedAIKernelService>();
services.AddSingleton<IKernelService, Services.OpenAI.KernelService>();
services.AddSingleton<IPasteFormatExecutor, PasteFormatExecutor>();
services.AddSingleton<OptionsViewModel>();
}).Build();

View File

@@ -11,7 +11,7 @@
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="16" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:AnimatedContentControl">

View File

@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="AdvancedPaste.Controls.ClipboardHistoryItemPreviewControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:AdvancedPaste.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:AdvancedPaste.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
mc:Ignorable="d">
<UserControl.Resources>
<converters:DateTimeToFriendlyStringConverter x:Key="DateTimeToFriendlyStringConverter" />
<tkconverters:BoolToVisibilityConverter x:Name="BoolToVisibilityConverter" />
</UserControl.Resources>
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource SubtleFillColorSecondaryBrush}" CornerRadius="16,0,0,16">
<Grid>
<!-- Image preview -->
<Image
Source="{x:Bind ClipboardItem.Image, Mode=OneWay}"
Stretch="UniformToFill"
Visibility="{x:Bind HasImage, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<!-- Text preview -->
<TextBlock
Margin="8,0,0,0"
VerticalAlignment="Center"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind ClipboardItem.Content, Mode=OneWay}"
TextWrapping="Wrap"
Visibility="{x:Bind HasText, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<!-- Icon glyph fallback -->
<FontIcon
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="48"
Glyph="{x:Bind IconGlyph, Mode=OneWay}"
Visibility="{x:Bind HasGlyph, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
</Grid>
</Border>
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Spacing="2">
<TextBlock
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind Header, Mode=OneWay}"
TextWrapping="NoWrap" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Timestamp, Converter={StaticResource DateTimeToFriendlyStringConverter}, Mode=OneWay}" />
</StackPanel>
</Grid>
</UserControl>

View File

@@ -1,127 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using AdvancedPaste.Helpers;
using AdvancedPaste.Models;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
namespace AdvancedPaste.Controls
{
public sealed partial class ClipboardHistoryItemPreviewControl : UserControl
{
public static readonly DependencyProperty ClipboardItemProperty = DependencyProperty.Register(
nameof(ClipboardItem),
typeof(ClipboardItem),
typeof(ClipboardHistoryItemPreviewControl),
new PropertyMetadata(defaultValue: null, OnClipboardItemChanged));
public ClipboardItem ClipboardItem
{
get => (ClipboardItem)GetValue(ClipboardItemProperty);
set => SetValue(ClipboardItemProperty, value);
}
// Computed properties for display
public string Header => ClipboardItem != null ? GetHeaderFromFormat(ClipboardItem.Format) : string.Empty;
public string IconGlyph => ClipboardItem != null ? GetGlyphFromFormat(ClipboardItem.Format) : string.Empty;
public string ContentText => ClipboardItem?.Content ?? string.Empty;
public ImageSource ContentImage => ClipboardItem?.Image;
public DateTimeOffset? Timestamp => ClipboardItem?.Timestamp ?? ClipboardItem?.Item?.Timestamp;
public bool HasImage => ContentImage is not null;
public bool HasText => !string.IsNullOrEmpty(ContentText) && !HasImage;
public bool HasGlyph => !HasImage && !HasText && !string.IsNullOrEmpty(IconGlyph);
public ClipboardHistoryItemPreviewControl()
{
InitializeComponent();
}
private static void OnClipboardItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ClipboardHistoryItemPreviewControl control)
{
// Notify bindings that all computed properties may have changed
control.Bindings.Update();
}
}
private static string GetHeaderFromFormat(ClipboardFormat format)
{
// Check flags in priority order (most specific first)
if (format.HasFlag(ClipboardFormat.Image))
{
return GetStringOrFallback("ClipboardPreviewCategoryImage", "Image");
}
if (format.HasFlag(ClipboardFormat.Video))
{
return GetStringOrFallback("ClipboardPreviewCategoryVideo", "Video");
}
if (format.HasFlag(ClipboardFormat.Audio))
{
return GetStringOrFallback("ClipboardPreviewCategoryAudio", "Audio");
}
if (format.HasFlag(ClipboardFormat.File))
{
return GetStringOrFallback("ClipboardPreviewCategoryFile", "File");
}
if (format.HasFlag(ClipboardFormat.Text) || format.HasFlag(ClipboardFormat.Html))
{
return GetStringOrFallback("ClipboardPreviewCategoryText", "Text");
}
return GetStringOrFallback("ClipboardPreviewCategoryUnknown", "Clipboard");
}
private static string GetGlyphFromFormat(ClipboardFormat format)
{
// Check flags in priority order (most specific first)
if (format.HasFlag(ClipboardFormat.Image))
{
return "\uEB9F"; // Image icon
}
if (format.HasFlag(ClipboardFormat.Video))
{
return "\uE714"; // Video icon
}
if (format.HasFlag(ClipboardFormat.Audio))
{
return "\uE189"; // Audio icon
}
if (format.HasFlag(ClipboardFormat.File))
{
return "\uE8A5"; // File icon
}
if (format.HasFlag(ClipboardFormat.Text) || format.HasFlag(ClipboardFormat.Html))
{
return "\uE8D2"; // Text icon
}
return "\uE77B"; // Generic clipboard icon
}
private static string GetStringOrFallback(string resourceKey, string fallback)
{
var value = ResourceLoaderInstance.ResourceLoader.GetString(resourceKey);
return string.IsNullOrEmpty(value) ? fallback : value;
}
}
}

View File

@@ -7,21 +7,34 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:AdvancedPaste.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:settings="using:Microsoft.PowerToys.Settings.UI.Library"
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
xmlns:ui="using:CommunityToolkit.WinUI"
x:Name="PromptBoxControl"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<Color x:Key="AccentGradientColor">#65C8F2</Color>
<LinearGradientBrush x:Key="AccentGradientBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="#98EFFE" />
<GradientStop Offset="0.25" Color="#48B1E9" />
<GradientStop Offset="1.0" Color="{StaticResource AccentGradientColor}" />
</LinearGradientBrush>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<Color x:Key="AccentGradientColor">#005FB8</Color>
<LinearGradientBrush x:Key="AccentGradientBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0.0" Color="#4992C7" />
<GradientStop Offset="0.25" Color="#1353A0" />
<GradientStop Offset="1.0" Color="{StaticResource AccentGradientColor}" />
</LinearGradientBrush>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Color x:Key="AccentGradientColor">#48B1E9</Color>
<SolidColorBrush x:Key="AccentGradientBrush" Color="{StaticResource AccentGradientColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<LinearGradientBrush x:Name="IntelligentUnderlineGradient" StartPoint="0,0.5" EndPoint="1,0.5">
<GradientStop Offset="0.0" Color="#FF0078D4" />
<GradientStop Offset="0.42" Color="#FF464FEB" />
<GradientStop Offset="0.87" Color="#FFD660FF" />
<GradientStop Offset="1.0" Color="#FFFEA874" />
</LinearGradientBrush>
<x:Double x:Key="ModelSelectorButtonWidth">44</x:Double>
<Style x:Key="CustomTextBoxStyle" TargetType="TextBox">
<Setter Property="Foreground" Value="{ThemeResource TextControlForeground}" />
<Setter Property="Background" Value="{ThemeResource TextControlBackground}" />
@@ -142,7 +155,6 @@
Foreground="{ThemeResource TextControlHeaderForeground}"
TextWrapping="Wrap"
Visibility="Collapsed" />
<Border
x:Name="BorderElement"
Grid.Row="1"
@@ -156,32 +168,48 @@
BorderThickness="{TemplateBinding BorderThickness}"
Control.IsTemplateFocusTarget="True"
CornerRadius="{TemplateBinding CornerRadius}" />
<Rectangle
x:Name="FocusHighlighter"
<Viewbox
Grid.Row="1"
Grid.RowSpan="1"
Grid.ColumnSpan="4"
Height="2"
Margin="12,0,12,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Fill="{StaticResource IntelligentUnderlineGradient}"
RadiusX="1"
RadiusY="1"
Visibility="Collapsed" />
<Grid Grid.Row="1" Width="{StaticResource ModelSelectorButtonWidth}">
<ProgressRing
Width="20"
Height="20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsActive="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
IsIndeterminate="{Binding DataContext.HasIndeterminateTransformProgress, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Maximum="100"
Minimum="0"
Visibility="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}"
Value="{Binding DataContext.TransformProgress, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
</Grid>
Width="16"
Height="16"
Margin="8,0,0,0">
<StackPanel
Margin="0"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ProgressRing
Width="30"
Height="30"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsActive="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
IsIndeterminate="{Binding DataContext.HasIndeterminateTransformProgress, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Maximum="100"
Minimum="0"
Visibility="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}"
Value="{Binding DataContext.TransformProgress, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
<StackPanel
Margin="0"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Visibility="{Binding DataContext.IsBusy, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<Image
x:Name="AIGlyphImage"
AutomationProperties.AccessibilityView="Raw"
Source="/Assets/AdvancedPaste/SemanticKernel.svg"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BoolToVisibilityConverter}}" />
<PathIcon
x:Name="AIGlyph"
AutomationProperties.AccessibilityView="Raw"
Data="M128 766q0-42 24-77t65-48l178-57q32-11 61-30t52-42q50-50 71-114l58-179q13-40 48-65t78-26q42 0 77 24t50 65l58 177q21 66 72 117 49 50 117 72l176 58q43 14 69 48t26 80q0 41-25 76t-64 49l-178 58q-66 21-117 72-32 32-51 73t-33 84-26 83-30 73-45 51-71 20q-42 0-77-24t-49-65l-58-178q-8-25-19-47t-28-43q-34-43-77-68t-89-41-89-27-78-29-55-45-21-75zm1149 7q-76-29-145-53t-129-60-104-88-73-138l-57-176-67 176q-18 48-42 89t-60 78q-34 34-76 61t-89 43l-177 57q75 29 144 53t127 60 103 89 73 137l57 176 67-176q37-97 103-168t168-103l177-57zm-125 759q0-31 20-57t49-36l99-32q34-11 53-34t30-51 20-59 20-54 33-41 58-16q32 0 59 19t38 50q6 20 11 40t13 40 17 38 25 34q16 17 39 26t48 18 49 16 44 20 31 32 12 50q0 33-18 60t-51 38q-19 6-39 11t-41 13-39 17-34 25q-24 25-35 62t-24 73-35 61-68 25q-32 0-59-19t-38-50q-6-18-11-39t-13-41-17-40-24-33q-18-17-41-27t-47-17-49-15-43-20-30-33-12-54zm583 4q-43-13-74-30t-55-41-40-55-32-74q-12 41-29 72t-42 55-55 42-71 31q81 23 128 71t71 129q15-43 31-74t40-54 53-40 75-32z"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Visibility="{Binding DataContext.IsAdvancedAIEnabled, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
</StackPanel>
</StackPanel>
</Viewbox>
<ScrollViewer
x:Name="ContentElement"
Grid.Row="1"
@@ -251,6 +279,12 @@
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="AIGlyph" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="AIGlyphImage" Storyboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="0.4" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding PlaceholderForeground, RelativeSource={RelativeSource TemplatedParent}, TargetNullValue={ThemeResource TextControlPlaceholderForegroundDisabled}}" />
</ObjectAnimationUsingKeyFrames>
@@ -280,10 +314,7 @@
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundFocused}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusHighlighter" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<LinearGradientBrush MappingMode="Absolute" StartPoint="0,0" EndPoint="0,2">
@@ -300,7 +331,7 @@
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderThemeThicknessFocused}" />
</ObjectAnimationUsingKeyFrames>-->
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundFocused}" />
</ObjectAnimationUsingKeyFrames>
@@ -333,8 +364,6 @@
FalseValue="Visible"
TrueValue="Collapsed" />
<converters:CountToVisibilityConverter x:Key="CountToVisibilityConverter" />
<converters:CountToInvertedVisibilityConverter x:Key="CountToInvertedVisibilityConverter" />
<converters:ServiceTypeToIconConverter x:Key="ServiceTypeToIconConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="PromptBoxGrid" Loaded="Grid_Loaded">
@@ -345,19 +374,18 @@
<local:AnimatedContentControl
x:Name="Loader"
MinHeight="48"
CornerRadius="16">
CornerRadius="8">
<Grid>
<TextBox
x:Name="InputTxtBox"
HorizontalAlignment="Stretch"
x:FieldModifier="public"
CornerRadius="16"
DataContext="{x:Bind ViewModel}"
IsEnabled="{x:Bind ViewModel.ClipboardHasData, Mode=OneWay}"
KeyDown="InputTxtBox_KeyDown"
PlaceholderText="{x:Bind ViewModel.InputTxtBoxPlaceholderText, Mode=OneWay}"
Style="{StaticResource CustomTextBoxStyle}"
TabIndex="1"
TabIndex="0"
Text="{x:Bind ViewModel.Query, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="InputTxtBoxTooltip" />
@@ -517,139 +545,6 @@
</Flyout>
</FlyoutBase.AttachedFlyout>
</TextBox>
<DropDownButton
x:Name="AIProviderButton"
x:Uid="AIProviderButton"
MinWidth="{StaticResource ModelSelectorButtonWidth}"
Margin="1,1,0,2"
Padding="0,0,4,0"
VerticalAlignment="Stretch"
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
BorderThickness="0,0,1,0"
CornerRadius="16,0,0,16"
Style="{StaticResource SubtleDropDownButtonStyle}"
TabIndex="0"
Visibility="{x:Bind ViewModel.IsBusy, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<ToolTipService.ToolTip>
<TextBlock Text="{x:Bind ViewModel.ActiveAIProviderTooltip, Mode=OneWay}" TextWrapping="WrapWholeWords" />
</ToolTipService.ToolTip>
<DropDownButton.Content>
<Image
x:Name="AIProviderIcon"
Width="16"
Height="16"
AutomationProperties.AccessibilityView="Raw"
Source="{x:Bind ViewModel.ActiveAIProvider?.ServiceType, Mode=OneWay, Converter={StaticResource ServiceTypeToIconConverter}}" />
</DropDownButton.Content>
<DropDownButton.Flyout>
<Flyout
Opened="AIProviderFlyout_Opened"
Placement="Bottom"
ShouldConstrainToRootBounds="False">
<Grid
Width="386"
Margin="-4"
RowSpacing="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
x:Uid="AIProvidersFlyoutHeader"
Grid.Row="0"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<ListView
x:Name="AIProviderListView"
Grid.Row="1"
MaxHeight="320"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource OverlayCornerRadius}"
ItemsSource="{x:Bind ViewModel.AIProviders, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollMode="Auto"
SelectedItem="{x:Bind ViewModel.ActiveAIProvider, Mode=OneWay}"
SelectionChanged="AIProviderListView_SelectionChanged"
SelectionMode="Single"
Visibility="{x:Bind ViewModel.AIProviders.Count, Mode=OneWay, Converter={StaticResource CountToVisibilityConverter}}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Spacing="2" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate x:DataType="settings:PasteAIProviderDefinition">
<Grid Padding="0,8,0,8" ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image
Width="20"
Height="20"
AutomationProperties.AccessibilityView="Raw"
Source="{x:Bind ServiceType, Mode=OneWay, Converter={StaticResource ServiceTypeToIconConverter}}" />
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Spacing="2">
<TextBlock Text="{x:Bind DisplayName, Mode=OneWay}" TextTrimming="CharacterEllipsis" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ServiceType, Mode=OneWay}" />
</StackPanel>
<Border
Grid.Column="2"
Padding="2,0,2,0"
VerticalAlignment="Center"
BorderBrush="{ThemeResource ControlStrokeColorSecondary}"
BorderThickness="1"
CornerRadius="{StaticResource ControlCornerRadius}"
Visibility="{x:Bind IsLocalModel, Mode=OneWay}">
<TextBlock
x:Uid="LocalModelBadge"
AutomationProperties.AccessibilityView="Raw"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</Border>
<!--<Border
Grid.Column="2"
Padding="2,0,2,0"
VerticalAlignment="Center"
BorderBrush="{ThemeResource TertiaryButtonBorderBrush}"
BorderThickness="1"
CornerRadius="{StaticResource ControlCornerRadius}"
Visibility="{x:Bind EnableAdvanceAI}">
<TextBlock
AutomationProperties.AccessibilityView="Raw"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="ADVANCED" />
</Border>-->
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock
x:Uid="AIProvidersEmptyText"
Grid.Row="1"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
TextWrapping="WrapWholeWords"
Visibility="{x:Bind ViewModel.AIProviders.Count, Mode=OneWay, Converter={StaticResource CountToInvertedVisibilityConverter}}" />
<HyperlinkButton
x:Uid="AIProvidersManageButtonContent"
Grid.Row="2"
HorizontalAlignment="Right"
Command="{x:Bind ViewModel.OpenSettingsCommand, Mode=OneWay}" />
</Grid>
</Flyout>
</DropDownButton.Flyout>
</DropDownButton>
<Grid
Width="32"
Height="32"
@@ -667,9 +562,10 @@
Command="{x:Bind GenerateCustomAICommand}"
Content="{ui:FontIcon Glyph=&#xE724;,
FontSize=16}"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
IsEnabled="{x:Bind ViewModel.IsCustomAIAvailable, Mode=OneWay}"
Style="{StaticResource SubtleButtonStyle}"
TabIndex="2"
TabIndex="1"
Visibility="{x:Bind ViewModel.Query.Length, Mode=OneWay, Converter={StaticResource CountToVisibilityConverter}}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="SendBtnToolTip" TextWrapping="WrapWholeWords" />
@@ -744,8 +640,8 @@
x:Name="LoadingText"
x:Uid="LoadingText"
Grid.Row="1"
Margin="4,4,0,0"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
FontWeight="SemiBold"
Foreground="{ThemeResource AccentGradientBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Visibility="Collapsed">
<animations:Implicit.ShowAnimations>

View File

@@ -10,11 +10,9 @@ using AdvancedPaste.Models;
using AdvancedPaste.ViewModels;
using CommunityToolkit.Mvvm.Input;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
namespace AdvancedPaste.Controls
{
@@ -22,8 +20,6 @@ namespace AdvancedPaste.Controls
{
public OptionsViewModel ViewModel { get; private set; }
private bool _syncingProviderSelection;
public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.Register(
nameof(PlaceholderText),
typeof(string),
@@ -48,18 +44,6 @@ namespace AdvancedPaste.Controls
set => SetValue(FooterProperty, value);
}
public static readonly DependencyProperty ModelSelectorProperty = DependencyProperty.Register(
nameof(ModelSelector),
typeof(object),
typeof(PromptBox),
new PropertyMetadata(defaultValue: null));
public object ModelSelector
{
get => GetValue(ModelSelectorProperty);
set => SetValue(ModelSelectorProperty, value);
}
public PromptBox()
{
InitializeComponent();
@@ -76,11 +60,6 @@ namespace AdvancedPaste.Controls
var state = ViewModel.IsBusy ? "LoadingState" : ViewModel.PasteActionError.HasText ? "ErrorState" : "DefaultState";
VisualStateManager.GoToState(this, state, true);
}
if (e.PropertyName is nameof(ViewModel.ActiveAIProvider) or nameof(ViewModel.AIProviders))
{
SyncProviderSelection();
}
}
private void ViewModel_PreviewRequested(object sender, EventArgs e)
@@ -94,7 +73,6 @@ namespace AdvancedPaste.Controls
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
InputTxtBox.Focus(FocusState.Programmatic);
SyncProviderSelection();
}
[RelayCommand]
@@ -133,57 +111,5 @@ namespace AdvancedPaste.Controls
{
Loader.IsLoading = loading;
}
private void SyncProviderSelection()
{
if (AIProviderListView is null)
{
return;
}
try
{
_syncingProviderSelection = true;
AIProviderListView.SelectedItem = ViewModel.ActiveAIProvider;
}
finally
{
_syncingProviderSelection = false;
}
}
private void AIProviderFlyout_Opened(object sender, object e)
{
SyncProviderSelection();
}
private async void AIProviderListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_syncingProviderSelection)
{
return;
}
var flyout = FlyoutBase.GetAttachedFlyout(AIProviderButton);
if (AIProviderListView.SelectedItem is not PasteAIProviderDefinition provider)
{
return;
}
if (string.Equals(ViewModel.ActiveAIProvider?.Id, provider.Id, StringComparison.OrdinalIgnoreCase))
{
flyout?.Hide();
return;
}
if (ViewModel.SetActiveProviderCommand.CanExecute(provider))
{
await ViewModel.SetActiveProviderCommand.ExecuteAsync(provider);
SyncProviderSelection();
}
flyout?.Hide();
}
}
}

View File

@@ -1,24 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
namespace AdvancedPaste.Converters;
public sealed partial class CountToInvertedVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
bool hasItems = ((value is int intValue) && intValue > 0) || (value is IEnumerable enumerable && enumerable.GetEnumerator().MoveNext());
return targetType == typeof(Visibility)
? (hasItems ? Visibility.Collapsed : Visibility.Visible)
: !hasItems;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
=> throw new NotSupportedException();
}

View File

@@ -1,103 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.UI.Xaml.Data;
using Microsoft.Windows.ApplicationModel.Resources;
namespace AdvancedPaste.Converters
{
public sealed partial class DateTimeToFriendlyStringConverter : IValueConverter
{
private static readonly ResourceLoader _resources = new ResourceLoader();
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is not DateTimeOffset dto)
{
return string.Empty;
}
// Use local times to calculate relative values and formatting
var now = DateTimeOffset.Now;
var localValue = dto.ToLocalTime();
var culture = !string.IsNullOrEmpty(language)
? new CultureInfo(language)
: CultureInfo.CurrentCulture;
var delta = now - localValue;
// Future dates: fall back to date/time formatting
if (delta < TimeSpan.Zero)
{
return FormatDateAndTime(localValue, culture);
}
// < 1 minute
if (delta.TotalSeconds < 60)
{
return _resources.GetString("Relative_JustNow"); // "Just now"
}
// < 60 minutes
if (delta.TotalMinutes < 60)
{
var mins = (int)Math.Round(delta.TotalMinutes);
if (mins <= 1)
{
return _resources.GetString("Relative_MinuteAgo"); // "1 minute ago"
}
var fmt = _resources.GetString("Relative_MinutesAgo_Format"); // "{0} minutes ago"
return string.Format(culture, fmt, mins);
}
// Same calendar day → "Today, {time}"
var today = now.Date;
if (localValue.Date == today)
{
var time = localValue.ToString("t", culture); // localized short time
var fmt = _resources.GetString("Relative_Today_TimeFormat"); // "Today, {0}"
return string.Format(culture, fmt, time);
}
// Yesterday → "Yesterday, {time}"
if (localValue.Date == today.AddDays(-1))
{
var time = localValue.ToString("t", culture);
var fmt = _resources.GetString("Relative_Yesterday_TimeFormat"); // "Yesterday, {0}"
return string.Format(culture, fmt, time);
}
// Within last 7 days → "{Weekday}, {time}"
if (delta.TotalDays < 7)
{
var weekday = localValue.ToString("dddd", culture); // localized weekday
var time = localValue.ToString("t", culture);
var fmt = _resources.GetString("Relative_Weekday_TimeFormat"); // "{0}, {1}"
return string.Format(culture, fmt, weekday, time);
}
// Older → localized date + time
return FormatDateAndTime(localValue, culture);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
=> throw new NotSupportedException();
private static string FormatDateAndTime(DateTimeOffset localValue, CultureInfo culture)
{
// Use localized short date + short time
var date = localValue.ToString("d", culture);
var time = localValue.ToString("t", culture);
var fmt = _resources.GetString("Relative_Date_TimeFormat"); // "{0}, {1}"
return string.Format(culture, fmt, date, time);
}
}
}

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