Compare commits

..

1 Commits

Author SHA1 Message Date
Leilei Zhang
d6b3baae96 fix Bgcode official build error 2025-07-11 11:12:30 +08:00
507 changed files with 2181 additions and 12612 deletions

View File

@@ -282,12 +282,3 @@ xef
xes
PACKAGEVERSIONNUMBER
APPXMANIFESTVERSION
# MRU lists
CACHEWRITE
MRUCMPPROC
MRUINFO
REGSTR
# Misc Win32 APIs and PInvokes
INVOKEIDLIST

View File

@@ -38,7 +38,6 @@ ALLAPPS
ALLCHILDREN
ALLINPUT
Allman
Allmodule
ALLOWUNDO
ALLVIEW
ALPHATYPE
@@ -219,7 +218,6 @@ coclass
CODENAME
codereview
Codespaces
Coen
COINIT
colid
colorconv
@@ -247,7 +245,6 @@ CONTEXTMENUHANDLER
contractversion
CONTROLPARENT
copiedcolorrepresentation
coppied
copyable
COPYPEN
COREWINDOW
@@ -446,7 +443,6 @@ ERRORIMAGE
ERRORTITLE
ESettings
esrp
etd
ETDT
etl
etw
@@ -531,8 +527,8 @@ frm
FROMTOUCH
fsanitize
fsmgmt
fuzzingtesting
fxf
fuzzingtesting
FZE
gacutil
Gaeilge
@@ -737,7 +733,6 @@ INSTALLSTARTMENUSHORTCUT
INSTALLSTATE
Inste
Interlop
intput
INTRESOURCE
INVALIDARG
invalidoperatioexception
@@ -820,7 +815,6 @@ LMEM
LMENU
LOADFROMFILE
LOBYTE
localappdata
localpackage
LOCALSYSTEM
LOCATIONCHANGE
@@ -1123,7 +1117,6 @@ oldtheme
oleaut
OLECHAR
onebranch
OOBEUI
openas
opencode
OPENFILENAME
@@ -1389,7 +1382,6 @@ RIDEV
RIGHTSCROLLBAR
riid
RKey
Rns
RNumber
rop
ROUNDSMALL
@@ -1401,7 +1393,6 @@ Rsp
rstringalnum
rstringalpha
rstringdigit
rtb
RTB
RTLREADING
rtm
@@ -1536,7 +1527,6 @@ SLGP
sln
SMALLICON
smartphone
smileys
SMTO
SNAPPROCESS
snk
@@ -1623,8 +1613,6 @@ svgz
SVSI
SWFO
SWP
SWPNOSIZE
SWPNOZORDER
SWRESTORE
symbolrequestprod
SYMCACHE
@@ -1764,8 +1752,8 @@ Uptool
urld
Usb
USEDEFAULT
USEFILEATTRIBUTES
USEINSTALLERFORTEST
USEFILEATTRIBUTES
USESHOWWINDOW
USESTDHANDLES
USRDLL

View File

@@ -4,7 +4,7 @@
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [ ] Closes: #xxx
- [ ] **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

View File

@@ -43,7 +43,6 @@ stages:
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
runTests: true
useVSPreview: ${{ parameters.useVSPreview }}
timeoutInMinutes: 90
- stage: OneFuzz
displayName: Fuzz ${{ parameters.platform }}

View File

@@ -38,11 +38,6 @@ parameters:
displayName: "Build Using Visual Studio Preview"
default: false
- name: enableAOT
type: boolean
displayName: "Enable AOT (Ahead-of-Time) Compilation for CmdPal"
default: true
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
variables:
@@ -100,7 +95,7 @@ extends:
useManagedIdentity: $(SigningUseManagedIdentity)
clientId: $(SigningOriginalClientId)
# Have msbuild use the release nuget config profile
additionalBuildOptions: /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:EnableCmdPalAOT=${{ parameters.enableAOT }}
additionalBuildOptions: /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config"
beforeBuildSteps:
# Sets versions for all PowerToy created DLLs
- pwsh: |-

View File

@@ -81,12 +81,6 @@ parameters:
- 'src/modules/previewpane/SvgPreviewHandler/SvgPreviewHandler.csproj'
- 'src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.csproj'
- 'src/modules/FileLocksmith/FileLocksmithUI/FileLocksmithUI.csproj'
- name: timeoutInMinutes
type: number
default: 240
- name: cancelTimeoutInMinutes
type: number
default: 1
jobs:
- job: ${{ parameters.jobName }}
@@ -129,8 +123,8 @@ jobs:
${{ else }}:
RestoreAdditionalProjectSourcesArg: ''
displayName: Build
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }}
timeoutInMinutes: 240
cancelTimeoutInMinutes: 1
templateContext: # Required when this template is hosted in 1ES PT
outputs:
- output: pipelineArtifact

View File

@@ -123,7 +123,7 @@ jobs:
displayName: Stage UI Test Build Outputs
inputs:
sourceFolder: '$(Build.SourcesDirectory)'
contents: '**/$(BuildPlatform)/$(BuildConfiguration)/tests/**/*'
contents: '$(BuildPlatform)/$(BuildConfiguration)/**/*'
targetFolder: '$(JobOutputDirectory)\$(BuildPlatform)\$(BuildConfiguration)'
- publish: $(JobOutputDirectory)

View File

@@ -11,14 +11,12 @@ parameters:
- name: useLatestWebView2
type: boolean
default: false
- name: buildSource
type: string
default: "latestMainOfficialBuild"
displayName: "Build Source"
- name: specificBuildId
type: string
default: "xxxx"
displayName: "Build ID (for specific builds)"
- name: useLatestOfficialBuild
type: boolean
default: true
- name: useCurrentBranchBuild
type: boolean
default: false
- name: uiTestModules
type: object
default: []
@@ -45,7 +43,6 @@ jobs:
BuildConfiguration: ${{ parameters.configuration }}
SrcPath: $(Build.Repository.LocalPath)
TestArtifactsName: build-${{ variables.BuildPlatform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }}
isBuildNow: ${{ eq(parameters.buildSource, 'buildNow') }}
pool:
${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}:
${{ if ne(parameters.platform, 'ARM64') }}:
@@ -116,17 +113,16 @@ jobs:
& '$(build.sourcesdirectory)\.pipelines\InstallWinAppDriver.ps1'
displayName: Download and install WinAppDriver
- ${{ if not(variables.isBuildNow) }}:
- ${{ if eq(parameters.useLatestOfficialBuild, true) }}:
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'specific'
project: 'Dart'
definition: '76541'
${{ if eq(parameters.buildSource, 'specificBuildId') }}:
buildVersionToDownload: 'specific'
buildId: '${{ parameters.specificBuildId }}'
buildVersionToDownload: 'latestFromBranch'
${{ if eq(parameters.useCurrentBranchBuild, true) }}:
branchName: '$(Build.SourceBranch)'
${{ else }}:
buildVersionToDownload: 'latestFromBranch'
branchName: 'refs/heads/main'
artifactName: 'build-$(BuildPlatform)-Release'
targetPath: '$(Build.ArtifactStagingDirectory)'
@@ -137,7 +133,7 @@ jobs:
patterns: |
**/PowerToysSetup*.exe
- ${{ if not(variables.isBuildNow) }}:
- ${{ if eq(parameters.useLatestOfficialBuild, true) }}:
- ${{ if eq(parameters.installMode, 'peruser') }}:
- pwsh: |-
& "$(build.sourcesdirectory)\.pipelines\installPowerToys.ps1" -InstallMode "PerUser"
@@ -164,7 +160,6 @@ jobs:
vsTestVersion: 'toolsInstaller'
uiTests: true
rerunFailedTests: true
testRunTitle: 'UITests_${{ parameters.platform }}_${{ parameters.installMode }}'
# Since UITests-FancyZonesEditor.dll is generated in both UITests-FancyZonesEditor and UITests-FancyZones, removed one to avoid duplicate test runs
testAssemblyVer2: |
**\*UITest*.dll
@@ -173,7 +168,7 @@ jobs:
!**\UITests-FancyZones\**\UITests-FancyZonesEditor.dll
env:
platform: '$(TestPlatform)'
useInstallerForTest: ${{ not(variables.isBuildNow) }}
useInstallerForTest: ${{ parameters.useLatestOfficialBuild }}
- ${{ if ne(length(parameters.uiTestModules), 0) }}:
- ${{ each module in parameters.uiTestModules }}:
@@ -187,7 +182,6 @@ jobs:
vsTestVersion: 'toolsInstaller'
uiTests: true
rerunFailedTests: true
testRunTitle: 'UITests_${{ parameters.platform }}_${{ parameters.installMode }}'
testAssemblyVer2: |
**\*${{ module }}*.dll
!**\obj\**
@@ -195,4 +189,4 @@ jobs:
!**\UITests-FancyZones\**\UITests-FancyZonesEditor.dll
env:
platform: '$(TestPlatform)'
useInstallerForTest: ${{ not(variables.isBuildNow) }}
useInstallerForTest: ${{ parameters.useLatestOfficialBuild }}

View File

@@ -57,5 +57,4 @@ stages:
useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }}
${{ if eq(parameters.useLatestWinAppSDK, true) }}:
winAppSDKVersionNumber: ${{ parameters.winAppSDKVersionNumber }}
useExperimentalVersion: ${{ parameters.useExperimentalVersion }}
timeoutInMinutes: 90
useExperimentalVersion: ${{ parameters.useExperimentalVersion }}

View File

@@ -3,8 +3,6 @@ variables:
value: false
- name: EnablePipelineCache
value: true
- name: isBuildNow
value: ${{ eq(parameters.buildSource, 'buildNow') }}
parameters:
- name: buildPlatforms
@@ -21,25 +19,22 @@ parameters:
- name: useLatestWebView2
type: boolean
default: false
- name: buildSource
type: string
default: "latestMainOfficialBuild"
displayName: "Build Source"
values:
- latestMainOfficialBuild
- buildNow
- specificBuildId
- name: specificBuildId
type: string
default: 'xxxx'
displayName: "Build ID (only used when Build Source = specificBuildId)"
- name: useLatestOfficialBuild
type: boolean
default: true
- name: testBothInstallModes
type: boolean
default: true
- name: useCurrentBranchBuild
type: boolean
default: false
- name: uiTestModules
type: object
default: []
stages:
- ${{ each platform in parameters.buildPlatforms }}:
- ${{ if variables.isBuildNow }}:
- ${{ if eq(parameters.useLatestOfficialBuild, false) }}:
- stage: Build_${{ platform }}
displayName: Build ${{ platform }}
dependsOn: []
@@ -61,9 +56,8 @@ stages:
runTests: false
buildTests: true
useVSPreview: ${{ parameters.useVSPreview }}
timeoutInMinutes: 90
- ${{ if not(variables.isBuildNow) }}:
- ${{ if eq(parameters.useLatestOfficialBuild, true) }}:
- stage: BuildUITests_${{ platform }}
displayName: Build UI Tests Only
dependsOn: []
@@ -84,7 +78,7 @@ stages:
- ${{ if eq(platform, 'x64') }}:
- stage: Test_x64Win10
displayName: Test x64Win10
${{ if not(variables.isBuildNow) }}:
${{ if eq(parameters.useLatestOfficialBuild, true) }}:
dependsOn:
- BuildUITests_${{ platform }}
${{ else }}:
@@ -96,19 +90,19 @@ stages:
platform: x64Win10
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
uiTestModules: ${{ parameters.uiTestModules }}
# Additional per-user installation test
- ${{ if not(variables.isBuildNow) }}:
# Additional per-user installation test (when both modes are enabled)
- ${{ if and(eq(parameters.useLatestOfficialBuild, true), eq(parameters.testBothInstallModes, true)) }}:
- template: job-test-project.yml
parameters:
platform: x64Win10
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
uiTestModules: ${{ parameters.uiTestModules }}
installMode: 'peruser'
jobSuffix: '_PerUser'
@@ -116,7 +110,7 @@ stages:
- ${{ if eq(platform, 'x64') }}:
- stage: Test_x64Win11
displayName: Test x64Win11
${{ if not(variables.isBuildNow) }}:
${{ if eq(parameters.useLatestOfficialBuild, true) }}:
dependsOn:
- BuildUITests_${{ platform }}
${{ else }}:
@@ -128,19 +122,19 @@ stages:
platform: x64Win11
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
uiTestModules: ${{ parameters.uiTestModules }}
# Additional per-user installation test
- ${{ if not(variables.isBuildNow) }}:
# Additional per-user installation test (when both modes are enabled)
- ${{ if and(eq(parameters.useLatestOfficialBuild, true), eq(parameters.testBothInstallModes, true)) }}:
- template: job-test-project.yml
parameters:
platform: x64Win11
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
uiTestModules: ${{ parameters.uiTestModules }}
installMode: 'peruser'
jobSuffix: '_PerUser'
@@ -148,7 +142,7 @@ stages:
- ${{ if ne(platform, 'x64') }}:
- stage: Test_${{ platform }}
displayName: Test ${{ platform }}
${{ if not(variables.isBuildNow) }}:
${{ if eq(parameters.useLatestOfficialBuild, true) }}:
dependsOn:
- BuildUITests_${{ platform }}
${{ else }}:
@@ -160,19 +154,19 @@ stages:
platform: ${{ platform }}
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
uiTestModules: ${{ parameters.uiTestModules }}
# Additional per-user installation test
- ${{ if not(variables.isBuildNow) }}:
# Additional per-user installation test (when both modes are enabled)
- ${{ if and(eq(parameters.useLatestOfficialBuild, true), eq(parameters.testBothInstallModes, true)) }}:
- template: job-test-project.yml
parameters:
platform: ${{ platform }}
configuration: Release
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
buildSource: ${{ parameters.buildSource }}
specificBuildId: ${{ parameters.specificBuildId }}
useLatestOfficialBuild: ${{ parameters.useLatestOfficialBuild }}
useCurrentBranchBuild: ${{ parameters.useCurrentBranchBuild }}
uiTestModules: ${{ parameters.uiTestModules }}
installMode: 'peruser'
jobSuffix: '_PerUser'
jobSuffix: '_PerUser'

View File

@@ -19,7 +19,7 @@ Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude *UITest*,MouseJum
# Temporarily exclude All UI-Test, Fuzzer-Test projects because of Appium.WebDriver dependencies
$depsJsonFullFileName = $_.FullName
if ($depsJsonFullFileName -like "*CmdPal*" -or $depsJsonFullFileName -like "*CommandPalette*") {
if ($depsJsonFullFileName -like "*CmdPal*") {
return
}

View File

@@ -9,7 +9,6 @@
<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" />
<PackageVersion Include="CommunityToolkit.WinUI.Animations" Version="8.2.250402" />
@@ -22,7 +21,6 @@
<PackageVersion Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls.DataGrid" Version="7.1.2" />
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls.Markdown" Version="7.1.2" />
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock" Version="0.1.250703-build.2173" />
<PackageVersion Include="ControlzEx" Version="6.0.0" />
<PackageVersion Include="HelixToolkit" Version="2.24.0" />
<PackageVersion Include="HelixToolkit.Core.Wpf" Version="2.24.0" />
@@ -70,7 +68,6 @@
<PackageVersion Include="NLog.Schema" Version="5.2.8" />
<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" />
<PackageVersion Include="SharpCompress" Version="0.37.2" />
<!-- Don't update SkiaSharp.Views.WinUI to version 3.* branch as this brakes the HexBox control in Registry Preview. -->

View File

@@ -1496,9 +1496,7 @@ SOFTWARE.
- AdaptiveCards.Templating 2.0.5
- Appium.WebDriver 4.4.5
- Azure.AI.OpenAI 1.0.0-beta.17
- CoenM.ImageSharp.ImageHash 1.3.6
- CommunityToolkit.Common 8.4.0
- CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock 0.1.250703-build.2173
- CommunityToolkit.Mvvm 8.4.0
- CommunityToolkit.WinUI.Animations 8.2.250402
- CommunityToolkit.WinUI.Collections 8.2.250402
@@ -1581,3 +1579,4 @@ SOFTWARE.
- WinUIEx 2.2.0
- WPF-UI 3.0.5
- WyHash 1.0.5

View File

@@ -39,14 +39,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fancyzones", "fancyzones",
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesLib", "src\modules\fancyzones\FancyZonesLib\FancyZonesLib.vcxproj", "{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones.UnitTests", "src\modules\fancyzones\FancyZonesTests\UnitTests\UnitTests.vcxproj", "{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests-FancyZones", "src\modules\fancyzones\FancyZonesTests\UnitTests\UnitTests.vcxproj", "{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}"
ProjectSection(ProjectDependencies) = postProject
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{1AFB6476-670D-4E80-A464-657E01DFF482}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common.Lib.UnitTests", "src\common\UnitTests-CommonLib\UnitTests-CommonLib.vcxproj", "{1A066C63-64B3-45F8-92FE-664E1CCE8077}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests-CommonLib", "src\common\UnitTests-CommonLib\UnitTests-CommonLib.vcxproj", "{1A066C63-64B3-45F8-92FE-664E1CCE8077}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FancyZonesEditor", "src\modules\fancyzones\editor\FancyZonesEditor\FancyZonesEditor.csproj", "{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}"
EndProject
@@ -60,8 +60,11 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameLib", "src\modules\powerrename\lib\PowerRenameLib.vcxproj", "{51920F1F-C28C-4ADF-8660-4238766796C2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameTest", "src\modules\powerrename\testapp\PowerRenameTest.vcxproj", "{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}"
ProjectSection(ProjectDependencies) = postProject
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.UnitTests", "src\modules\powerrename\unittests\PowerRenameLibUnitTests.vcxproj", "{2151F984-E006-4A9F-92EF-C6DDE3DC8413}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUnitTests", "src\modules\powerrename\unittests\PowerRenameLibUnitTests.vcxproj", "{2151F984-E006-4A9F-92EF-C6DDE3DC8413}"
ProjectSection(ProjectDependencies) = postProject
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
@@ -77,7 +80,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageResizerUI", "src\modul
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageResizerExt", "src\modules\imageresizer\dll\ImageResizerExt.vcxproj", "{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageResizer.UnitTests", "src\modules\imageresizer\tests\ImageResizer.UnitTests.csproj", "{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageResizerUITest", "src\modules\imageresizer\tests\ImageResizerUITest.csproj", "{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.ActionRunner", "src\ActionRunner\ActionRunner.vcxproj", "{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}"
ProjectSection(ProjectDependencies) = postProject
@@ -149,13 +152,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PreviewHandlerCommon", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MarkdownPreviewHandler", "src\modules\previewpane\MarkdownPreviewHandler\MarkdownPreviewHandler.csproj", "{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.MarkdownPreviewHandler.UnitTests", "src\modules\previewpane\UnitTests-MarkdownPreviewHandler\Preview.MarkdownPreviewHandler.UnitTests.csproj", "{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-MarkdownPreviewHandler", "src\modules\previewpane\UnitTests-MarkdownPreviewHandler\UnitTests-MarkdownPreviewHandler.csproj", "{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SvgPreviewHandler", "src\modules\previewpane\SvgPreviewHandler\SvgPreviewHandler.csproj", "{DA425894-6E13-404F-8DCB-78584EC0557A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.SvgPreviewHandler.UnitTests", "src\modules\previewpane\UnitTests-SvgPreviewHandler\Preview.SvgPreviewHandler.UnitTests.csproj", "{060D75DA-2D1C-48E6-A4A1-6F0718B64661}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-SvgPreviewHandler", "src\modules\previewpane\UnitTests-SvgPreviewHandler\UnitTests-SvgPreviewHandler.csproj", "{060D75DA-2D1C-48E6-A4A1-6F0718B64661}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.PreviewHandlerCommon.UnitTests", "src\modules\previewpane\UnitTests-PreviewHandlerCommon\Preview.PreviewHandlerCommon.UnitTests.csproj", "{748417CA-F17E-487F-9411-CAFB6D3F4877}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PreviewHandlerCommon", "src\modules\previewpane\UnitTests-PreviewHandlerCommon\UnitTests-PreviewHandlerCommon.csproj", "{748417CA-F17E-487F-9411-CAFB6D3F4877}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "powerpreview", "src\modules\previewpane\powerpreview\powerpreview.vcxproj", "{217DF501-135C-4E38-BFC8-99D4821032EA}"
ProjectSection(ProjectDependencies) = postProject
@@ -192,7 +195,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ManagedCommon", "src\common
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Program.UnitTests", "src\modules\launcher\Plugins\Microsoft.Plugin.Program.UnitTests\Microsoft.Plugin.Program.UnitTests.csproj", "{42851751-CBC8-45A6-97F5-7A0753F7B4D1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.SvgThumbnailProvider.UnitTests", "src\modules\previewpane\UnitTests-SvgThumbnailProvider\Preview.SvgThumbnailProvider.UnitTests.csproj", "{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-SvgThumbnailProvider", "src\modules\previewpane\UnitTests-SvgThumbnailProvider\UnitTests-SvgThumbnailProvider.csproj", "{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SvgThumbnailProvider", "src\modules\previewpane\SvgThumbnailProvider\SvgThumbnailProvider.csproj", "{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}"
EndProject
@@ -213,6 +216,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Settings.UI.UnitTests", "sr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest\Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest.csproj", "{632BBE62-5421-49EA-835A-7FFA4F499BD6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Folder.UnitTests", "src\modules\launcher\Plugins\Microsoft.Plugin.Folder.UnitTests\Microsoft.Plugin.Folder.UnitTests.csproj", "{4FA206A5-F69F-4193-BF8F-F6EEB496734C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest-ColorPickerUI", "src\modules\colorPicker\UnitTest-ColorPickerUI\UnitTest-ColorPickerUI.csproj", "{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spdlog", "src\logging\logging.vcxproj", "{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.System", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.System\Microsoft.PowerToys.Run.Plugin.System.csproj", "{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}"
@@ -228,7 +235,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logger", "src\common\logger
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SettingsAPI", "src\common\SettingsAPI\SettingsAPI.vcxproj", "{6955446D-23F7-4023-9BB3-8657F904AF99}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.Interop.UnitTests", "src\common\interop\interop-tests\Common.Interop.UnitTests.csproj", "{58736667-1027-4AD7-BFDF-7A3A6474103A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Interop.Tests", "src\common\interop\interop-tests\Microsoft.Interop.Tests.csproj", "{58736667-1027-4AD7-BFDF-7A3A6474103A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "notifications", "notifications", "{D92131D6-7610-4D60-A7DB-1C169783F83B}"
EndProject
@@ -300,7 +307,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.UI", "src\common\Com
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfPreviewHandler", "src\modules\previewpane\PdfPreviewHandler\PdfPreviewHandler.csproj", "{69E1EE8D-143A-4060-9129-4658ACF14AAF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.PdfPreviewHandler.UnitTests", "src\modules\previewpane\UnitTests-PdfPreviewHandler\Preview.PdfPreviewHandler.UnitTests.csproj", "{ECC20689-002A-4354-95A6-B58DF089C6FF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PdfPreviewHandler", "src\modules\previewpane\UnitTests-PdfPreviewHandler\UnitTests-PdfPreviewHandler.csproj", "{ECC20689-002A-4354-95A6-B58DF089C6FF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.Registry", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Microsoft.PowerToys.Run.Plugin.Registry.csproj", "{4BABF3FE-3451-42FD-873F-3C332E18DCEF}"
EndProject
@@ -310,13 +317,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEngine", "sr
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEngineLibrary", "src\modules\keyboardmanager\KeyboardManagerEngineLibrary\KeyboardManagerEngineLibrary.vcxproj", "{E496B7FC-1E99-4BAB-849B-0E8367040B02}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManager.Engine.UnitTests", "src\modules\keyboardmanager\KeyboardManagerEngineTest\KeyboardManagerEngineTest.vcxproj", "{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEngineTest", "src\modules\keyboardmanager\KeyboardManagerEngineTest\KeyboardManagerEngineTest.vcxproj", "{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditor", "src\modules\keyboardmanager\KeyboardManagerEditor\KeyboardManagerEditor.vcxproj", "{8DF78B53-200E-451F-9328-01EB907193AE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorLibrary", "src\modules\keyboardmanager\KeyboardManagerEditorLibrary\KeyboardManagerEditorLibrary.vcxproj", "{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManager.Editor.UnitTests", "src\modules\keyboardmanager\KeyboardManagerEditorTest\KeyboardManagerEditorTest.vcxproj", "{62173D9A-6724-4C00-A1C8-FB646480A9EC}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorTest", "src\modules\keyboardmanager\KeyboardManagerEditorTest\KeyboardManagerEditorTest.vcxproj", "{62173D9A-6724-4C00-A1C8-FB646480A9EC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "awake", "awake", "{127F38E0-40AA-4594-B955-5616BF206882}"
EndProject
@@ -344,7 +351,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfThumbnailProvider", "src\modules\previewpane\PdfThumbnailProvider\PdfThumbnailProvider.csproj", "{11491FD8-F921-48BF-880C-7FEA185B80A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.PdfThumbnailProvider.UnitTests", "src\modules\previewpane\UnitTests-PdfThumbnailProvider\Preview.PdfThumbnailProvider.UnitTests.csproj", "{F40C3397-1834-4530-B2D9-8F8B8456BCDF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PdfThumbnailProvider", "src\modules\previewpane\UnitTests-PdfThumbnailProvider\UnitTests-PdfThumbnailProvider.csproj", "{F40C3397-1834-4530-B2D9-8F8B8456BCDF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsTerminal", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.csproj", "{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}"
EndProject
@@ -358,11 +365,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MouseHighlighter", "src\mod
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GcodeThumbnailProvider", "src\modules\previewpane\GcodeThumbnailProvider\GcodeThumbnailProvider.csproj", "{809AA252-E17A-4FA2-B0A1-0450976B763F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.GcodeThumbnailProvider.UnitTests", "src\modules\previewpane\UnitTests-GcodeThumbnailProvider\Preview.GcodeThumbnailProvider.UnitTests.csproj", "{133281D8-1BCE-4D07-B31E-796612A9609E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-GcodeThumbnailProvider", "src\modules\previewpane\UnitTests-GcodeThumbnailProvider\UnitTests-GcodeThumbnailProvider.csproj", "{133281D8-1BCE-4D07-B31E-796612A9609E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GcodePreviewHandler", "src\modules\previewpane\GcodePreviewHandler\GcodePreviewHandler.csproj", "{805306FF-A562-4415-8DEF-E493BDC45918}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.GcodePreviewHandler.UnitTests", "src\modules\previewpane\UnitTests-GcodePreviewHandler\Preview.GcodePreviewHandler.UnitTests.csproj", "{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-GcodePreviewHandler", "src\modules\previewpane\UnitTests-GcodePreviewHandler\UnitTests-GcodePreviewHandler.csproj", "{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AlwaysOnTop", "AlwaysOnTop", "{60CD2D4F-C3B9-4897-9821-FCA5098B41CE}"
EndProject
@@ -376,7 +383,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MousePointerCrosshairs", "s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StlThumbnailProvider", "src\modules\previewpane\StlThumbnailProvider\StlThumbnailProvider.csproj", "{F7C8C0F1-5431-4347-89D0-8E5354F93CF2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.StlThumbnailProvider.UnitTests", "src\modules\previewpane\UnitTests-StlThumbnailProvider\Preview.StlThumbnailProvider.UnitTests.csproj", "{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-StlThumbnailProvider", "src\modules\previewpane\UnitTests-StlThumbnailProvider\UnitTests-StlThumbnailProvider.csproj", "{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonacoPreviewHandler", "src\modules\previewpane\MonacoPreviewHandler\MonacoPreviewHandler.csproj", "{04B193D7-3E21-46B8-A958-89B63A8A69DE}"
EndProject
@@ -412,8 +419,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerOCR", "src\modules\Pow
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerOCRModuleInterface", "src\modules\PowerOCR\PowerOCRModuleInterface\PowerOCRModuleInterface.vcxproj", "{6AB6A2D6-F859-4A82-9184-0BD29C9F07D1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B1234567-1234-1234-1234-123456789ABC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.History", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.History\Microsoft.PowerToys.Run.Plugin.History.csproj", "{212AD910-8488-4036-BE20-326931B75FB2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MeasureTool", "MeasureTool", "{7AC943C9-52E8-44CF-9083-744D8049667B}"
@@ -435,7 +440,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostsUILib", "src\modules\H
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosts", "Hosts", "{F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostsEditor.UnitTests", "src\modules\Hosts\Hosts.Tests\HostsEditor.UnitTests.csproj", "{E2D03E0F-7A75-4813-9F4B-D8763D43FD3A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hosts.Tests", "src\modules\Hosts\Hosts.Tests\Hosts.Tests.csproj", "{E2D03E0F-7A75-4813-9F4B-D8763D43FD3A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HostsModuleInterface", "src\modules\Hosts\HostsModuleInterface\HostsModuleInterface.vcxproj", "{B41B888C-7DB8-4747-B262-4062E05A230D}"
EndProject
@@ -461,8 +466,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.Common", "src\modules\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.FilePreviewer", "src\modules\peek\Peek.FilePreviewer\Peek.FilePreviewer.csproj", "{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Peek.UITests", "src\modules\peek\Peek.UITests\Peek.UITests.csproj", "{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MarkdownPreviewHandlerCpp", "src\modules\previewpane\MarkdownPreviewHandlerCpp\MarkdownPreviewHandlerCpp.vcxproj", "{ED9A1AC6-AEB0-4569-A6E9-E1696182B545}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GcodePreviewHandlerCpp", "src\modules\previewpane\GcodePreviewHandlerCpp\GcodePreviewHandlerCpp.vcxproj", "{5A5DD09D-723A-44D3-8F2B-293584C3D731}"
@@ -527,6 +530,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CropAndLockModuleInterface"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cmdNotFound", "cmdNotFound", "{4C0D0746-BE5B-49EE-BD5D-A7811628AE8B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-FancyZonesEditor", "src\modules\fancyzones\UnitTests-FancyZonesEditor\UnitTests-FancyZonesEditor.csproj", "{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EnvironmentVariables", "EnvironmentVariables", "{538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvironmentVariablesUILib", "src\modules\EnvironmentVariables\EnvironmentVariablesUILib\EnvironmentVariablesUILib.csproj", "{51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA}"
@@ -541,9 +546,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QoiPreviewHandlerCpp", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QoiPreviewHandler", "src\modules\previewpane\QoiPreviewHandler\QoiPreviewHandler.csproj", "{6B04803D-B418-4833-A67E-B0FC966636A5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.QoiPreviewHandler.UnitTests", "src\modules\previewpane\UnitTests-QoiPreviewHandler\Preview.QoiPreviewHandler.UnitTests.csproj", "{3940AD4D-F748-4BE4-9083-85769CD553EF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-QoiPreviewHandler", "src\modules\previewpane\UnitTests-QoiPreviewHandler\UnitTests-QoiPreviewHandler.csproj", "{3940AD4D-F748-4BE4-9083-85769CD553EF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preview.QoiThumbnailProvider.UnitTests", "src\modules\previewpane\UnitTests-QoiThumbnailProvider\Preview.QoiThumbnailProvider.UnitTests.csproj", "{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-QoiThumbnailProvider", "src\modules\previewpane\UnitTests-QoiThumbnailProvider\UnitTests-QoiThumbnailProvider.csproj", "{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdNotFoundModuleInterface", "src\modules\cmdNotFound\CmdNotFoundModuleInterface\CmdNotFoundModuleInterface.vcxproj", "{0014D652-901F-4456-8D65-06FC5F997FB0}"
EndProject
@@ -559,6 +564,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RegistryPreview", "src\modu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvironmentVariables", "src\modules\EnvironmentVariables\EnvironmentVariables\EnvironmentVariables.csproj", "{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UITests-FancyZones", "src\modules\fancyzones\UITests-FancyZones\UITests-FancyZones.csproj", "{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UITests-FancyZonesEditor", "src\modules\fancyzones\UITests-FancyZonesEditor\UITests-FancyZonesEditor.csproj", "{3A9A791E-94A9-49F8-8401-C11CE288D5FB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FancyZonesEditorCommon", "src\modules\fancyzones\FancyZonesEditorCommon\FancyZonesEditorCommon.csproj", "{C0974915-8A1D-4BF0-977B-9587D3807AB7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DSC", "DSC", "{557C4636-D7E1-4838-A504-7D19B725EE95}"
@@ -595,7 +604,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WindowProperties", "WindowP
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WorkspacesLib", "src\modules\Workspaces\WorkspacesLib\WorkspacesLib.vcxproj", "{B31FCC55-B5A4-4EA7-B414-2DCEAE6AF332}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Workspaces.Lib.UnitTests", "src\modules\Workspaces\WorkspacesLib.UnitTests\WorkspacesLibUnitTests.vcxproj", "{A85D4D9F-9A39-4B5D-8B5A-9F2D5C9A8B4C}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WorkspacesLibUnitTests", "src\modules\Workspaces\WorkspacesLib.UnitTests\WorkspacesLibUnitTests.vcxproj", "{A85D4D9F-9A39-4B5D-8B5A-9F2D5C9A8B4C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorkspacesLauncherUI", "src\modules\Workspaces\WorkspacesLauncherUI\WorkspacesLauncherUI.csproj", "{9C53CC25-0623-4569-95BC-B05410675EE3}"
EndProject
@@ -671,6 +680,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSea
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WinGet", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WinGet\Microsoft.CmdPal.Ext.WinGet.csproj", "{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.UnitTests", "src\modules\AdvancedPaste\AdvancedPaste.UnitTests\AdvancedPaste.UnitTests.csproj", "{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.FuzzTests", "src\modules\AdvancedPaste\AdvancedPaste.FuzzTests\AdvancedPaste.FuzzTests.csproj", "{7F5B9557-5878-4438-A721-3E28296BA193}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ZoomIt", "ZoomIt", "{DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomIt", "src\modules\ZoomIt\ZoomIt\ZoomIt.vcxproj", "{0A84F764-3A88-44CD-AA96-41BDBD48627B}"
@@ -687,17 +700,19 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeyboardManagerEditorUI", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerEditorLibraryWrapper", "src\modules\keyboardmanager\KeyboardManagerEditorLibraryWrapper\KeyboardManagerEditorLibraryWrapper.vcxproj", "{4382A954-179A-4078-92AF-715187DFFF50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HostsEditor.FuzzTests", "src\modules\Hosts\Hosts.FuzzTests\HostsEditor.FuzzTests.csproj", "{EBED240C-8702-452D-B764-6DB9DA9179AF}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hosts.FuzzTests", "src\modules\Hosts\Hosts.FuzzTests\Hosts.FuzzTests.csproj", "{EBED240C-8702-452D-B764-6DB9DA9179AF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HostsEditor.UITests", "src\modules\Hosts\Hosts.UITests\HostsEditor.UITests.csproj", "{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hosts.UITests", "src\modules\Hosts\Hosts.UITests\Hosts.UITests.csproj", "{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegistryPreview.FuzzTests", "src\modules\registrypreview\RegistryPreview.FuzzTests\RegistryPreview.FuzzTests.csproj", "{5702B3CC-8575-48D5-83D8-15BB42269CD3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZones.FuzzTests", "src\modules\fancyzones\FancyZones.FuzzTests\FancyZones.FuzzTests.csproj", "{0217E86E-3476-9946-DE8E-9D200CEBD47A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalKeyboardService", "src\modules\cmdpal\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj", "{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzTests", "src\modules\powerrename\PowerRename.FuzzingTest\PowerRename.FuzzingTest.vcxproj", "{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzingTest", "src\modules\powerrename\PowerRename.FuzzingTest\PowerRename.FuzzingTest.vcxproj", "{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BgcodePreviewHandler", "src\modules\previewpane\BgcodePreviewHandler\BgcodePreviewHandler.csproj", "{9E0CBC06-F29A-4810-B93C-97D53863B95E}"
EndProject
@@ -707,86 +722,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BgcodeThumbnailProviderCpp"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BgcodeThumbnailProvider", "src\modules\previewpane\BgcodeThumbnailProvider\BgcodeThumbnailProvider.csproj", "{9BC1C986-1E97-4D07-A7B1-CE226C239EFA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Preview.BgcodePreviewHandler.UnitTests", "src\modules\previewpane\UnitTests-BgcodePreviewHandler\Preview.BgcodePreviewHandler.UnitTests.csproj", "{99CA1509-FB73-456E-AFAF-AB89C017BD72}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests-BgcodePreviewHandler", "src\modules\previewpane\UnitTests-BgcodePreviewHandler\UnitTests-BgcodePreviewHandler.csproj", "{99CA1509-FB73-456E-AFAF-AB89C017BD72}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Preview.BgcodeThumbnailProvider.UnitTests", "src\modules\previewpane\UnitTests-BgcodeThumbnailProvider\Preview.BgcodeThumbnailProvider.UnitTests.csproj", "{61CBF221-9452-4934-B685-146285E080D7}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests-BgcodeThumbnailProvider", "src\modules\previewpane\UnitTests-BgcodeThumbnailProvider\UnitTests-BgcodeThumbnailProvider.csproj", "{61CBF221-9452-4934-B685-146285E080D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MouseUtils.UITests", "src\modules\MouseUtils\MouseUtils.UITests\MouseUtils.UITests.csproj", "{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workspaces.Editor.UITests", "src\modules\Workspaces\WorkspacesEditorUITest\Workspaces.Editor.UITests.csproj", "{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesEditorUITest", "src\modules\Workspaces\WorkspacesEditorUITest\WorkspacesEditorUITest.csproj", "{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorEngineCommon", "src\common\CalculatorEngineCommon\CalculatorEngineCommon.vcxproj", "{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedCsWin32", "src\common\ManagedCsWin32\ManagedCsWin32.csproj", "{14AFD976-B4D2-49D0-9E6C-AA93CC061B8A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerRename.UITests", "src\modules\powerrename\PowerRenameUITest\PowerRename.UITests.csproj", "{9D3F3793-EFE3-4525-8782-238015DABA62}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Core.ViewModels", "src\modules\cmdpal\Microsoft.CmdPal.Core.ViewModels\Microsoft.CmdPal.Core.ViewModels.csproj", "{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0E556541-6A45-42CB-AE49-EE5A9BE05E7C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{27D9CB3A-46D1-402C-9273-F88CB8AC42F7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B9617A31-0F0A-4397-851D-BF2FBEE32D7F}"
ProjectSection(SolutionItems) = preProject
src\modules\launcher\Plugins\Microsoft.Plugin.Folder.UnitTests\Microsoft.Plugin.Folder.UnitTests.csproj = src\modules\launcher\Plugins\Microsoft.Plugin.Folder.UnitTests\Microsoft.Plugin.Folder.UnitTests.csproj
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{1C48CD47-D610-463A-A53C-AF82DD6C47E7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D9BD324E-1D80-44AA-8E7B-73EB00944434}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8EF25507-2575-4ADE-BF7E-D23376903AB8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerOCR.UITests", "src\modules\PowerOCR\PowerOCR-UITests\PowerOCR.UITests.csproj", "{070AC093-C9F2-20AD-0BCD-F318FC2761EA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{2C318EC3-BA86-4372-B1BC-DB0F33C208B2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BFFB607F-7C78-434B-86B9-DA4C8196A1B5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{66E1534A-1587-42B2-912F-45C994D32904}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{E885E71F-0B34-4A03-B13B-20F4E05E90BB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{264B412F-DB8B-4CF8-A74B-96998B183045}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3527BF37-DFC5-4309-A032-29278CA21328}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{68328142-5B31-4715-BCBB-7B6345EE0971}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.FuzzTests", "src\modules\AdvancedPaste\AdvancedPaste.FuzzTests\AdvancedPaste.FuzzTests.csproj", "{4122388B-59E4-CDB0-0338-EA6881DF86F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.UnitTests", "src\modules\AdvancedPaste\AdvancedPaste.UnitTests\AdvancedPaste.UnitTests.csproj", "{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.UITests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.UITests\Microsoft.CmdPal.UITests.csproj", "{6748A29D-DA6A-033A-825B-752295FF6AA0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZones.FuzzTests", "src\modules\fancyzones\FancyZones.FuzzTests\FancyZones.FuzzTests.csproj", "{6EABCF9A-6526-441F-932F-658B1DC3E403}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZones.UITests", "src\modules\fancyzones\FancyZones.UITests\FancyZones.UITests.csproj", "{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZonesEditor.UITests", "src\modules\fancyzones\FancyZonesEditor.UITests\FancyZonesEditor.UITests.csproj", "{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZonesEditor.UnitTests", "src\modules\fancyzones\FancyZonesEditor.UnitTests\FancyZonesEditor.UnitTests.csproj", "{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorPickerUI.UnitTests", "src\modules\colorPicker\ColorPickerUI.UnitTests\ColorPickerUI.UnitTests.csproj", "{F93C2817-C846-4259-84D8-B39A6B57C8DE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8131151D-B0E9-4E18-84A5-E5F946C4480A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Calc.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Calc.UnitTests\Microsoft.CmdPal.Ext.Calc.UnitTests.csproj", "{E816D7AC-4688-4ECB-97CC-3D8E798F3825}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Registry.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Registry.UnitTests\Microsoft.CmdPal.Ext.Registry.UnitTests.csproj", "{E816D7AD-4688-4ECB-97CC-3D8E798F3826}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.System.UnitTests\Microsoft.CmdPal.Ext.System.UnitTests.csproj", "{E816D7AE-4688-4ECB-97CC-3D8E798F3827}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.TimeDate.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.TimeDate.UnitTests\Microsoft.CmdPal.Ext.TimeDate.UnitTests.csproj", "{E816D7AF-4688-4ECB-97CC-3D8E798F3828}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WindowWalker.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.WindowWalker.UnitTests\Microsoft.CmdPal.Ext.WindowWalker.UnitTests.csproj", "{E816D7B0-4688-4ECB-97CC-3D8E798F3829}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.UnitTestBase", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.UnitTestsBase\Microsoft.CmdPal.Ext.UnitTestBase.csproj", "{00D8659C-2068-40B6-8B86-759CD6284BBB}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerRenameUITest", "src\modules\powerrename\PowerRenameUITest\PowerRenameUITest.csproj", "{9D3F3793-EFE3-4525-8782-238015DABA62}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1188,6 +1136,22 @@ Global
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|ARM64.Build.0 = Release|ARM64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.ActiveCfg = Release|x64
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.Build.0 = Release|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|ARM64.ActiveCfg = Debug|ARM64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|ARM64.Build.0 = Debug|ARM64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.ActiveCfg = Debug|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.Build.0 = Debug|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|ARM64.ActiveCfg = Release|ARM64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|ARM64.Build.0 = Release|ARM64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.ActiveCfg = Release|x64
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.Build.0 = Release|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|ARM64.ActiveCfg = Debug|ARM64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|ARM64.Build.0 = Debug|ARM64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.ActiveCfg = Debug|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.Build.0 = Debug|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|ARM64.ActiveCfg = Release|ARM64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|ARM64.Build.0 = Release|ARM64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.ActiveCfg = Release|x64
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.Build.0 = Release|x64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|ARM64.Build.0 = Debug|ARM64
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64
@@ -1856,14 +1820,6 @@ Global
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|ARM64.Build.0 = Release|ARM64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x64.ActiveCfg = Release|x64
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x64.Build.0 = Release|x64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}.Debug|ARM64.ActiveCfg = Debug|ARM64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}.Debug|ARM64.Build.0 = Debug|ARM64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}.Debug|x64.ActiveCfg = Debug|x64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}.Debug|x64.Build.0 = Debug|x64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}.Release|ARM64.ActiveCfg = Release|ARM64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}.Release|ARM64.Build.0 = Release|ARM64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}.Release|x64.ActiveCfg = Release|x64
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5}.Release|x64.Build.0 = Release|x64
{ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|ARM64.ActiveCfg = Debug|ARM64
{ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|ARM64.Build.0 = Debug|ARM64
{ED9A1AC6-AEB0-4569-A6E9-E1696182B545}.Debug|x64.ActiveCfg = Debug|x64
@@ -2080,6 +2036,14 @@ Global
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|ARM64.Build.0 = Release|ARM64
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x64.ActiveCfg = Release|x64
{3157FA75-86CF-4EE2-8F62-C43F776493C6}.Release|x64.Build.0 = Release|x64
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Debug|ARM64.Build.0 = Debug|ARM64
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Debug|x64.ActiveCfg = Debug|x64
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Debug|x64.Build.0 = Debug|x64
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Release|ARM64.ActiveCfg = Release|ARM64
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Release|ARM64.Build.0 = Release|ARM64
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Release|x64.ActiveCfg = Release|x64
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B}.Release|x64.Build.0 = Release|x64
{51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA}.Debug|ARM64.Build.0 = Debug|Any CPU
{51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -2204,6 +2168,22 @@ Global
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|ARM64.Build.0 = Release|ARM64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|x64.ActiveCfg = Release|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|x64.Build.0 = Release|x64
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}.Debug|ARM64.ActiveCfg = Debug|ARM64
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}.Debug|ARM64.Build.0 = Debug|ARM64
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}.Debug|x64.ActiveCfg = Debug|x64
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}.Debug|x64.Build.0 = Debug|x64
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}.Release|ARM64.ActiveCfg = Release|ARM64
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}.Release|ARM64.Build.0 = Release|ARM64
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}.Release|x64.ActiveCfg = Release|x64
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52}.Release|x64.Build.0 = Release|x64
{3A9A791E-94A9-49F8-8401-C11CE288D5FB}.Debug|ARM64.ActiveCfg = Debug|ARM64
{3A9A791E-94A9-49F8-8401-C11CE288D5FB}.Debug|ARM64.Build.0 = Debug|ARM64
{3A9A791E-94A9-49F8-8401-C11CE288D5FB}.Debug|x64.ActiveCfg = Debug|x64
{3A9A791E-94A9-49F8-8401-C11CE288D5FB}.Debug|x64.Build.0 = Debug|x64
{3A9A791E-94A9-49F8-8401-C11CE288D5FB}.Release|ARM64.ActiveCfg = Release|ARM64
{3A9A791E-94A9-49F8-8401-C11CE288D5FB}.Release|ARM64.Build.0 = Release|ARM64
{3A9A791E-94A9-49F8-8401-C11CE288D5FB}.Release|x64.ActiveCfg = Release|x64
{3A9A791E-94A9-49F8-8401-C11CE288D5FB}.Release|x64.Build.0 = Release|x64
{C0974915-8A1D-4BF0-977B-9587D3807AB7}.Debug|ARM64.ActiveCfg = Debug|ARM64
{C0974915-8A1D-4BF0-977B-9587D3807AB7}.Debug|ARM64.Build.0 = Debug|ARM64
{C0974915-8A1D-4BF0-977B-9587D3807AB7}.Debug|x64.ActiveCfg = Debug|x64
@@ -2528,6 +2508,22 @@ Global
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.ActiveCfg = Release|x64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.Build.0 = Release|x64
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.Deploy.0 = Release|x64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|ARM64.Build.0 = Debug|ARM64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|x64.ActiveCfg = Debug|x64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|x64.Build.0 = Debug|x64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|ARM64.ActiveCfg = Release|ARM64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|ARM64.Build.0 = Release|ARM64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x64.ActiveCfg = Release|x64
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x64.Build.0 = Release|x64
{7F5B9557-5878-4438-A721-3E28296BA193}.Debug|ARM64.ActiveCfg = Debug|ARM64
{7F5B9557-5878-4438-A721-3E28296BA193}.Debug|ARM64.Build.0 = Debug|ARM64
{7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x64.ActiveCfg = Debug|x64
{7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x64.Build.0 = Debug|x64
{7F5B9557-5878-4438-A721-3E28296BA193}.Release|ARM64.ActiveCfg = Release|ARM64
{7F5B9557-5878-4438-A721-3E28296BA193}.Release|ARM64.Build.0 = Release|ARM64
{7F5B9557-5878-4438-A721-3E28296BA193}.Release|x64.ActiveCfg = Release|x64
{7F5B9557-5878-4438-A721-3E28296BA193}.Release|x64.Build.0 = Release|x64
{0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|ARM64.Build.0 = Debug|ARM64
{0A84F764-3A88-44CD-AA96-41BDBD48627B}.Debug|x64.ActiveCfg = Debug|x64
@@ -2620,6 +2616,14 @@ Global
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.Build.0 = Release|ARM64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.ActiveCfg = Release|x64
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.Build.0 = Release|x64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.Build.0 = Debug|ARM64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.ActiveCfg = Debug|x64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.Build.0 = Debug|x64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.ActiveCfg = Release|ARM64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.Build.0 = Release|ARM64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.ActiveCfg = Release|x64
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.Build.0 = Release|x64
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|ARM64.ActiveCfg = Debug|ARM64
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|ARM64.Build.0 = Debug|ARM64
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|x64.ActiveCfg = Debug|x64
@@ -2722,134 +2726,6 @@ Global
{9D3F3793-EFE3-4525-8782-238015DABA62}.Release|ARM64.Build.0 = Release|ARM64
{9D3F3793-EFE3-4525-8782-238015DABA62}.Release|x64.ActiveCfg = Release|x64
{9D3F3793-EFE3-4525-8782-238015DABA62}.Release|x64.Build.0 = Release|x64
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}.Debug|ARM64.ActiveCfg = Debug|ARM64
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}.Debug|ARM64.Build.0 = Debug|ARM64
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}.Debug|x64.ActiveCfg = Debug|x64
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}.Debug|x64.Build.0 = Debug|x64
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}.Release|ARM64.ActiveCfg = Release|ARM64
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}.Release|ARM64.Build.0 = Release|ARM64
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}.Release|x64.ActiveCfg = Release|x64
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027}.Release|x64.Build.0 = Release|x64
{070AC093-C9F2-20AD-0BCD-F318FC2761EA}.Debug|ARM64.ActiveCfg = Debug|ARM64
{070AC093-C9F2-20AD-0BCD-F318FC2761EA}.Debug|ARM64.Build.0 = Debug|ARM64
{070AC093-C9F2-20AD-0BCD-F318FC2761EA}.Debug|x64.ActiveCfg = Debug|x64
{070AC093-C9F2-20AD-0BCD-F318FC2761EA}.Debug|x64.Build.0 = Debug|x64
{070AC093-C9F2-20AD-0BCD-F318FC2761EA}.Release|ARM64.ActiveCfg = Release|ARM64
{070AC093-C9F2-20AD-0BCD-F318FC2761EA}.Release|ARM64.Build.0 = Release|ARM64
{070AC093-C9F2-20AD-0BCD-F318FC2761EA}.Release|x64.ActiveCfg = Release|x64
{070AC093-C9F2-20AD-0BCD-F318FC2761EA}.Release|x64.Build.0 = Release|x64
{4122388B-59E4-CDB0-0338-EA6881DF86F0}.Debug|ARM64.ActiveCfg = Debug|ARM64
{4122388B-59E4-CDB0-0338-EA6881DF86F0}.Debug|ARM64.Build.0 = Debug|ARM64
{4122388B-59E4-CDB0-0338-EA6881DF86F0}.Debug|x64.ActiveCfg = Debug|x64
{4122388B-59E4-CDB0-0338-EA6881DF86F0}.Debug|x64.Build.0 = Debug|x64
{4122388B-59E4-CDB0-0338-EA6881DF86F0}.Release|ARM64.ActiveCfg = Release|ARM64
{4122388B-59E4-CDB0-0338-EA6881DF86F0}.Release|ARM64.Build.0 = Release|ARM64
{4122388B-59E4-CDB0-0338-EA6881DF86F0}.Release|x64.ActiveCfg = Release|x64
{4122388B-59E4-CDB0-0338-EA6881DF86F0}.Release|x64.Build.0 = Release|x64
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}.Debug|ARM64.ActiveCfg = Debug|ARM64
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}.Debug|ARM64.Build.0 = Debug|ARM64
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}.Debug|x64.ActiveCfg = Debug|x64
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}.Debug|x64.Build.0 = Debug|x64
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}.Release|ARM64.ActiveCfg = Release|ARM64
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}.Release|ARM64.Build.0 = Release|ARM64
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}.Release|x64.ActiveCfg = Release|x64
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55}.Release|x64.Build.0 = Release|x64
{6748A29D-DA6A-033A-825B-752295FF6AA0}.Debug|ARM64.ActiveCfg = Debug|ARM64
{6748A29D-DA6A-033A-825B-752295FF6AA0}.Debug|ARM64.Build.0 = Debug|ARM64
{6748A29D-DA6A-033A-825B-752295FF6AA0}.Debug|x64.ActiveCfg = Debug|x64
{6748A29D-DA6A-033A-825B-752295FF6AA0}.Debug|x64.Build.0 = Debug|x64
{6748A29D-DA6A-033A-825B-752295FF6AA0}.Release|ARM64.ActiveCfg = Release|ARM64
{6748A29D-DA6A-033A-825B-752295FF6AA0}.Release|ARM64.Build.0 = Release|ARM64
{6748A29D-DA6A-033A-825B-752295FF6AA0}.Release|x64.ActiveCfg = Release|x64
{6748A29D-DA6A-033A-825B-752295FF6AA0}.Release|x64.Build.0 = Release|x64
{6EABCF9A-6526-441F-932F-658B1DC3E403}.Debug|ARM64.ActiveCfg = Debug|ARM64
{6EABCF9A-6526-441F-932F-658B1DC3E403}.Debug|ARM64.Build.0 = Debug|ARM64
{6EABCF9A-6526-441F-932F-658B1DC3E403}.Debug|x64.ActiveCfg = Debug|x64
{6EABCF9A-6526-441F-932F-658B1DC3E403}.Debug|x64.Build.0 = Debug|x64
{6EABCF9A-6526-441F-932F-658B1DC3E403}.Release|ARM64.ActiveCfg = Release|ARM64
{6EABCF9A-6526-441F-932F-658B1DC3E403}.Release|ARM64.Build.0 = Release|ARM64
{6EABCF9A-6526-441F-932F-658B1DC3E403}.Release|x64.ActiveCfg = Release|x64
{6EABCF9A-6526-441F-932F-658B1DC3E403}.Release|x64.Build.0 = Release|x64
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}.Debug|ARM64.ActiveCfg = Debug|ARM64
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}.Debug|ARM64.Build.0 = Debug|ARM64
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}.Debug|x64.ActiveCfg = Debug|x64
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}.Debug|x64.Build.0 = Debug|x64
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}.Release|ARM64.ActiveCfg = Release|ARM64
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}.Release|ARM64.Build.0 = Release|ARM64
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}.Release|x64.ActiveCfg = Release|x64
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15}.Release|x64.Build.0 = Release|x64
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}.Debug|ARM64.Build.0 = Debug|ARM64
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}.Debug|x64.ActiveCfg = Debug|x64
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}.Debug|x64.Build.0 = Debug|x64
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}.Release|ARM64.ActiveCfg = Release|ARM64
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}.Release|ARM64.Build.0 = Release|ARM64
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}.Release|x64.ActiveCfg = Release|x64
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83}.Release|x64.Build.0 = Release|x64
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}.Debug|ARM64.Build.0 = Debug|ARM64
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}.Debug|x64.ActiveCfg = Debug|x64
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}.Debug|x64.Build.0 = Debug|x64
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}.Release|ARM64.ActiveCfg = Release|ARM64
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}.Release|ARM64.Build.0 = Release|ARM64
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}.Release|x64.ActiveCfg = Release|x64
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9}.Release|x64.Build.0 = Release|x64
{F93C2817-C846-4259-84D8-B39A6B57C8DE}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F93C2817-C846-4259-84D8-B39A6B57C8DE}.Debug|ARM64.Build.0 = Debug|ARM64
{F93C2817-C846-4259-84D8-B39A6B57C8DE}.Debug|x64.ActiveCfg = Debug|x64
{F93C2817-C846-4259-84D8-B39A6B57C8DE}.Debug|x64.Build.0 = Debug|x64
{F93C2817-C846-4259-84D8-B39A6B57C8DE}.Release|ARM64.ActiveCfg = Release|ARM64
{F93C2817-C846-4259-84D8-B39A6B57C8DE}.Release|ARM64.Build.0 = Release|ARM64
{F93C2817-C846-4259-84D8-B39A6B57C8DE}.Release|x64.ActiveCfg = Release|x64
{F93C2817-C846-4259-84D8-B39A6B57C8DE}.Release|x64.Build.0 = Release|x64
{E816D7AC-4688-4ECB-97CC-3D8E798F3825}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E816D7AC-4688-4ECB-97CC-3D8E798F3825}.Debug|ARM64.Build.0 = Debug|ARM64
{E816D7AC-4688-4ECB-97CC-3D8E798F3825}.Debug|x64.ActiveCfg = Debug|x64
{E816D7AC-4688-4ECB-97CC-3D8E798F3825}.Debug|x64.Build.0 = Debug|x64
{E816D7AC-4688-4ECB-97CC-3D8E798F3825}.Release|ARM64.ActiveCfg = Release|ARM64
{E816D7AC-4688-4ECB-97CC-3D8E798F3825}.Release|ARM64.Build.0 = Release|ARM64
{E816D7AC-4688-4ECB-97CC-3D8E798F3825}.Release|x64.ActiveCfg = Release|x64
{E816D7AC-4688-4ECB-97CC-3D8E798F3825}.Release|x64.Build.0 = Release|x64
{E816D7AD-4688-4ECB-97CC-3D8E798F3826}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E816D7AD-4688-4ECB-97CC-3D8E798F3826}.Debug|ARM64.Build.0 = Debug|ARM64
{E816D7AD-4688-4ECB-97CC-3D8E798F3826}.Debug|x64.ActiveCfg = Debug|x64
{E816D7AD-4688-4ECB-97CC-3D8E798F3826}.Debug|x64.Build.0 = Debug|x64
{E816D7AD-4688-4ECB-97CC-3D8E798F3826}.Release|ARM64.ActiveCfg = Release|ARM64
{E816D7AD-4688-4ECB-97CC-3D8E798F3826}.Release|ARM64.Build.0 = Release|ARM64
{E816D7AD-4688-4ECB-97CC-3D8E798F3826}.Release|x64.ActiveCfg = Release|x64
{E816D7AD-4688-4ECB-97CC-3D8E798F3826}.Release|x64.Build.0 = Release|x64
{E816D7AE-4688-4ECB-97CC-3D8E798F3827}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E816D7AE-4688-4ECB-97CC-3D8E798F3827}.Debug|ARM64.Build.0 = Debug|ARM64
{E816D7AE-4688-4ECB-97CC-3D8E798F3827}.Debug|x64.ActiveCfg = Debug|x64
{E816D7AE-4688-4ECB-97CC-3D8E798F3827}.Debug|x64.Build.0 = Debug|x64
{E816D7AE-4688-4ECB-97CC-3D8E798F3827}.Release|ARM64.ActiveCfg = Release|ARM64
{E816D7AE-4688-4ECB-97CC-3D8E798F3827}.Release|ARM64.Build.0 = Release|ARM64
{E816D7AE-4688-4ECB-97CC-3D8E798F3827}.Release|x64.ActiveCfg = Release|x64
{E816D7AE-4688-4ECB-97CC-3D8E798F3827}.Release|x64.Build.0 = Release|x64
{E816D7AF-4688-4ECB-97CC-3D8E798F3828}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E816D7AF-4688-4ECB-97CC-3D8E798F3828}.Debug|ARM64.Build.0 = Debug|ARM64
{E816D7AF-4688-4ECB-97CC-3D8E798F3828}.Debug|x64.ActiveCfg = Debug|x64
{E816D7AF-4688-4ECB-97CC-3D8E798F3828}.Debug|x64.Build.0 = Debug|x64
{E816D7AF-4688-4ECB-97CC-3D8E798F3828}.Release|ARM64.ActiveCfg = Release|ARM64
{E816D7AF-4688-4ECB-97CC-3D8E798F3828}.Release|ARM64.Build.0 = Release|ARM64
{E816D7AF-4688-4ECB-97CC-3D8E798F3828}.Release|x64.ActiveCfg = Release|x64
{E816D7AF-4688-4ECB-97CC-3D8E798F3828}.Release|x64.Build.0 = Release|x64
{E816D7B0-4688-4ECB-97CC-3D8E798F3829}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E816D7B0-4688-4ECB-97CC-3D8E798F3829}.Debug|ARM64.Build.0 = Debug|ARM64
{E816D7B0-4688-4ECB-97CC-3D8E798F3829}.Debug|x64.ActiveCfg = Debug|x64
{E816D7B0-4688-4ECB-97CC-3D8E798F3829}.Debug|x64.Build.0 = Debug|x64
{E816D7B0-4688-4ECB-97CC-3D8E798F3829}.Release|ARM64.ActiveCfg = Release|ARM64
{E816D7B0-4688-4ECB-97CC-3D8E798F3829}.Release|ARM64.Build.0 = Release|ARM64
{E816D7B0-4688-4ECB-97CC-3D8E798F3829}.Release|x64.ActiveCfg = Release|x64
{E816D7B0-4688-4ECB-97CC-3D8E798F3829}.Release|x64.Build.0 = Release|x64
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Debug|ARM64.ActiveCfg = Debug|ARM64
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Debug|ARM64.Build.0 = Debug|ARM64
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Debug|x64.ActiveCfg = Debug|x64
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Debug|x64.Build.0 = Debug|x64
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|ARM64.ActiveCfg = Release|ARM64
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|ARM64.Build.0 = Release|ARM64
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.ActiveCfg = Release|x64
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2858,26 +2734,26 @@ Global
{3BB8493E-D18E-4485-A320-CB40F90F55AE} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9} = {264B412F-DB8B-4CF8-A74B-96998B183045}
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{1A066C63-64B3-45F8-92FE-664E1CCE8077} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{51920F1F-C28C-4ADF-8660-4238766796C2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{2151F984-E006-4A9F-92EF-C6DDE3DC8413} = {66E1534A-1587-42B2-912F-45C994D32904}
{2151F984-E006-4A9F-92EF-C6DDE3DC8413} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{6C7F47CC-2151-44A3-A546-41C70025132C} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {6C7F47CC-2151-44A3-A546-41C70025132C}
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B} = {6C7F47CC-2151-44A3-A546-41C70025132C}
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8} = {0E556541-6A45-42CB-AE49-EE5A9BE05E7C}
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8} = {6C7F47CC-2151-44A3-A546-41C70025132C}
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{38BDB927-829B-4C65-9CD9-93FB05D66D65} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} = {C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68}
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80} = {C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68}
{FF742965-9A80-41A5-B042-D6C7D3A21708} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{FF742965-9A80-41A5-B042-D6C7D3A21708} = {C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68}
{4AFC9975-2456-4C70-94A4-84073C1CED93} = {C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68}
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{4D971245-7A70-41D5-BAA0-DDB5684CAF51} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
@@ -2890,29 +2766,31 @@ Global
{2F305555-C296-497E-AC20-5FA1B237996A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{AF2349B8-E5B6-4004-9502-687C1C7730B1} = {2F305555-C296-497E-AC20-5FA1B237996A}
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB} = {2F305555-C296-497E-AC20-5FA1B237996A}
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A} = {2F305555-C296-497E-AC20-5FA1B237996A}
{DA425894-6E13-404F-8DCB-78584EC0557A} = {2F305555-C296-497E-AC20-5FA1B237996A}
{060D75DA-2D1C-48E6-A4A1-6F0718B64661} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{748417CA-F17E-487F-9411-CAFB6D3F4877} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{060D75DA-2D1C-48E6-A4A1-6F0718B64661} = {2F305555-C296-497E-AC20-5FA1B237996A}
{748417CA-F17E-487F-9411-CAFB6D3F4877} = {2F305555-C296-497E-AC20-5FA1B237996A}
{217DF501-135C-4E38-BFC8-99D4821032EA} = {2F305555-C296-497E-AC20-5FA1B237996A}
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{08C8C05F-0362-41BC-818C-724572DF8B06} = {C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68}
{5D00D290-4016-4CFE-9E41-1E7C724509BA} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{4AED67B6-55FD-486F-B917-E543DEE2CB3C} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{42851751-CBC8-45A6-97F5-7A0753F7B4D1} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{42851751-CBC8-45A6-97F5-7A0753F7B4D1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E} = {2F305555-C296-497E-AC20-5FA1B237996A}
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD} = {2F305555-C296-497E-AC20-5FA1B237996A}
{655C9AF2-18D3-4DA6-80E4-85504A7722BA} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
{BA58206B-1493-4C75-BFEA-A85768A1E156} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
{1D78B84B-CA39-406C-98F4-71F7EC266CC0} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{03276A39-D4E9-417C-8FFD-200B0EE5E871} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{B81FB7B6-D30E-428F-908A-41422EFC1172} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{0F85E674-34AE-443D-954C-8321EB8B93B1} = {E885E71F-0B34-4A03-B13B-20F4E05E90BB}
{632BBE62-5421-49EA-835A-7FFA4F499BD6} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{B81FB7B6-D30E-428F-908A-41422EFC1172} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{0F85E674-34AE-443D-954C-8321EB8B93B1} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
{632BBE62-5421-49EA-835A-7FFA4F499BD6} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{4FA206A5-F69F-4193-BF8F-F6EEB496734C} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F} = {E4E03FE0-94FD-47C7-88C5-F17D0AA549D3}
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{DA5A6FE9-0040-40CC-83CC-764AE5306590} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{DA5A6FE9-0040-40CC-83CC-764AE5306590} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{0351ADA4-0C32-4652-9BA0-41F7B602372B} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD} = {E4E03FE0-94FD-47C7-88C5-F17D0AA549D3}
{6955446D-23F7-4023-9BB3-8657F904AF99} = {1AFB6476-670D-4E80-A464-657E01DFF482}
@@ -2931,20 +2809,20 @@ Global
{8F62026A-294B-41C6-8839-87463613F216} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{C3A17DCA-217B-462C-BB0C-BE086AF80081} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{69E1EE8D-143A-4060-9129-4658ACF14AAF} = {2F305555-C296-497E-AC20-5FA1B237996A}
{ECC20689-002A-4354-95A6-B58DF089C6FF} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{ECC20689-002A-4354-95A6-B58DF089C6FF} = {2F305555-C296-497E-AC20-5FA1B237996A}
{4BABF3FE-3451-42FD-873F-3C332E18DCEF} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{E496B7FC-1E99-4BAB-849B-0E8367040B02} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466} = {D9BD324E-1D80-44AA-8E7B-73EB00944434}
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{8DF78B53-200E-451F-9328-01EB907193AE} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {D9BD324E-1D80-44AA-8E7B-73EB00944434}
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{127F38E0-40AA-4594-B955-5616BF206882} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882}
{D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882}
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{106CBECA-0701-4FC3-838C-9DF816A19AE2} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
{2EDB3EB4-FA92-4BFF-B2D8-566584837231} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
@@ -2952,27 +2830,27 @@ Global
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{11491FD8-F921-48BF-880C-7FEA185B80A1} = {2F305555-C296-497E-AC20-5FA1B237996A}
{F40C3397-1834-4530-B2D9-8F8B8456BCDF} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{F40C3397-1834-4530-B2D9-8F8B8456BCDF} = {2F305555-C296-497E-AC20-5FA1B237996A}
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{4ED320BC-BA04-4D42-8D15-CBE62151F08B} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{4ED320BC-BA04-4D42-8D15-CBE62151F08B} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{322566EF-20DC-43A6-B9F8-616AF942579A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{E94FD11C-0591-456F-899F-EFC0CA548336} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{809AA252-E17A-4FA2-B0A1-0450976B763F} = {2F305555-C296-497E-AC20-5FA1B237996A}
{133281D8-1BCE-4D07-B31E-796612A9609E} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{133281D8-1BCE-4D07-B31E-796612A9609E} = {2F305555-C296-497E-AC20-5FA1B237996A}
{805306FF-A562-4415-8DEF-E493BDC45918} = {2F305555-C296-497E-AC20-5FA1B237996A}
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3} = {2F305555-C296-497E-AC20-5FA1B237996A}
{60CD2D4F-C3B9-4897-9821-FCA5098B41CE} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{1DC3BE92-CE89-43FB-8110-9C043A2FE7A2} = {60CD2D4F-C3B9-4897-9821-FCA5098B41CE}
{48A0A19E-A0BE-4256-ACF8-CC3B80291AF9} = {60CD2D4F-C3B9-4897-9821-FCA5098B41CE}
{9F94B303-5E21-4364-9362-64426F8DB932} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{EAE14C0E-7A6B-45DA-9080-A7D8C077BA6E} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{F7C8C0F1-5431-4347-89D0-8E5354F93CF2} = {2F305555-C296-497E-AC20-5FA1B237996A}
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{F1F6B6B6-9F18-4A17-8B5C-97DF552C53DC} = {2F305555-C296-497E-AC20-5FA1B237996A}
{04B193D7-3E21-46B8-A958-89B63A8A69DE} = {2F305555-C296-497E-AC20-5FA1B237996A}
{5BDBD6C9-A31F-4CEB-871A-5E9E709197EF} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{FD464B4C-2F68-4D06-91E7-4208146C41F5} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{8FE5A5EE-1B59-401C-9FB3-B04ECD3E29C1} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{FD464B4C-2F68-4D06-91E7-4208146C41F5} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{8FE5A5EE-1B59-401C-9FB3-B04ECD3E29C1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{020A7474-3601-4160-A159-D7B70B77B15F} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
{27718999-C175-450A-861C-89F911E16A88} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{1DBBB112-4BB1-444B-8EBB-E66555C76BA6} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
@@ -2986,7 +2864,6 @@ Global
{A50C70A6-2DA0-4027-B90E-B1A40755A8A5} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{25C91A4E-BA4E-467A-85CD-8B62545BF674} = {A50C70A6-2DA0-4027-B90E-B1A40755A8A5}
{6AB6A2D6-F859-4A82-9184-0BD29C9F07D1} = {A50C70A6-2DA0-4027-B90E-B1A40755A8A5}
{B1234567-1234-1234-1234-123456789ABC} = {A50C70A6-2DA0-4027-B90E-B1A40755A8A5}
{212AD910-8488-4036-BE20-326931B75FB2} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{7AC943C9-52E8-44CF-9083-744D8049667B} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{54A93AF7-60C7-4F6C-99D2-FBB1F75F853A} = {7AC943C9-52E8-44CF-9083-744D8049667B}
@@ -2995,7 +2872,7 @@ Global
{C97D9A5D-206C-454E-997E-009E227D7F02} = {0F14491C-6369-4C45-AAA8-135814E66E6B}
{31D1C81D-765F-4446-AA62-E743F6325049} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{F05E590D-AD46-42BE-9C25-6A63ADD2E3EA} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{E2D03E0F-7A75-4813-9F4B-D8763D43FD3A} = {1C48CD47-D610-463A-A53C-AF82DD6C47E7}
{E2D03E0F-7A75-4813-9F4B-D8763D43FD3A} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{B41B888C-7DB8-4747-B262-4062E05A230D} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{AB82E5DD-C32D-4F28-9746-2C780846188E} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{57175EC7-92A5-4C1E-8244-E3FBCA2A81DE} = {AB82E5DD-C32D-4F28-9746-2C780846188E}
@@ -3008,7 +2885,6 @@ Global
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A5} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
{ED9A1AC6-AEB0-4569-A6E9-E1696182B545} = {2F305555-C296-497E-AC20-5FA1B237996A}
{5A5DD09D-723A-44D3-8F2B-293584C3D731} = {2F305555-C296-497E-AC20-5FA1B237996A}
{B3E869C4-8210-4EBD-A621-FF4C4AFCBFA9} = {2F305555-C296-497E-AC20-5FA1B237996A}
@@ -3025,7 +2901,7 @@ Global
{A663E672-B26D-4EC0-BEAB-FE2E424AC46F} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
{8A08D663-4995-40E3-B42C-3F910625F284} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{923DF87C-CA99-4D1C-B1D2-959174E95BFA} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{D5E42C63-57C5-4EF6-AECE-1E2FCA725B77} = {2C318EC3-BA86-4372-B1BC-DB0F33C208B2}
{D5E42C63-57C5-4EF6-AECE-1E2FCA725B77} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{D962A009-834F-4EEC-AABB-430DF8F98E39} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{9873BA05-4C41-4819-9283-CF45D795431B} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{FC373B24-3293-453C-AAF5-CF2909DCEE6A} = {9873BA05-4C41-4819-9283-CF45D795431B}
@@ -3036,11 +2912,12 @@ Global
{9EBAA524-0EDA-470B-95D4-39383285CBB2} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{500DED3E-CFB5-4ED5-ACC6-02B3D6DC336D} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{D095BE44-1F2E-463E-A494-121892A75EA2} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{90F9FA90-2C20-4004-96E6-F3B78151F5A5} = {B9617A31-0F0A-4397-851D-BF2FBEE32D7F}
{90F9FA90-2C20-4004-96E6-F3B78151F5A5} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{3B227528-4BA6-4CAF-B44A-A10C78A64849} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{F5E1146E-B7B3-4E11-85FD-270A500BD78C} = {3B227528-4BA6-4CAF-B44A-A10C78A64849}
{3157FA75-86CF-4EE2-8F62-C43F776493C6} = {3B227528-4BA6-4CAF-B44A-A10C78A64849}
{4C0D0746-BE5B-49EE-BD5D-A7811628AE8B} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{FC8EB78F-F061-4BD9-A3F6-507BEA965E2B} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{538ED0BB-B863-4B20-98CC-BCDF7FA0B68A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA} = {538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}
{B9420661-B0E4-4241-ABD4-4A27A1F64250} = {538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}
@@ -3048,8 +2925,8 @@ Global
{D949EC7D-48A9-4279-95D5-078E7FD1F048} = {2F305555-C296-497E-AC20-5FA1B237996A}
{3BAF9C81-A194-4925-A035-5E24A5D1E542} = {2F305555-C296-497E-AC20-5FA1B237996A}
{6B04803D-B418-4833-A67E-B0FC966636A5} = {2F305555-C296-497E-AC20-5FA1B237996A}
{3940AD4D-F748-4BE4-9083-85769CD553EF} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{3940AD4D-F748-4BE4-9083-85769CD553EF} = {2F305555-C296-497E-AC20-5FA1B237996A}
{F8FFFC12-A31A-4AFA-B3DF-14DCF42B5E38} = {2F305555-C296-497E-AC20-5FA1B237996A}
{0014D652-901F-4456-8D65-06FC5F997FB0} = {4C0D0746-BE5B-49EE-BD5D-A7811628AE8B}
{799A50D8-DE89-4ED1-8FF8-AD5A9ED8C0CA} = {AB82E5DD-C32D-4F28-9746-2C780846188E}
{9D52FD25-EF90-4F9A-A015-91EFC5DAF54F} = {AB82E5DD-C32D-4F28-9746-2C780846188E}
@@ -3057,6 +2934,8 @@ Global
{02DD46D3-F761-47D9-8894-2D6DA0124650} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{8E23E173-7127-4A5F-9F93-3049F2B68047} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8} = {538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}
{FE38FC07-1C05-4B57-ADA3-2FE2F53C6A52} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{3A9A791E-94A9-49F8-8401-C11CE288D5FB} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{C0974915-8A1D-4BF0-977B-9587D3807AB7} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{1D6893CB-BC0C-46A8-A76C-9728706CA51A} = {557C4636-D7E1-4838-A504-7D19B725EE95}
{8ACB33D9-C95B-47D4-8363-9731EE0930A0} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC}
@@ -3066,7 +2945,7 @@ Global
{BE126CBB-AE12-406A-9837-A05ACFCA57A7} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{14CB58B7-D280-4A7A-95DE-4B2DF14EA000} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{B31FCC55-B5A4-4EA7-B414-2DCEAE6AF332} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{A85D4D9F-9A39-4B5D-8B5A-9F2D5C9A8B4C} = {68328142-5B31-4715-BCBB-7B6345EE0971}
{A85D4D9F-9A39-4B5D-8B5A-9F2D5C9A8B4C} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{9C53CC25-0623-4569-95BC-B05410675EE3} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{45285DF2-9742-4ECA-9AC9-58951FC26489} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{3D63307B-9D27-44FD-B033-B26F39245B85} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
@@ -3074,7 +2953,7 @@ Global
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{37D07516-4185-43A4-924F-3C7A5D95ECF6} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{8F021B46-362B-485C-BFBA-CCF83E820CBD} = {8F62026A-294B-41C6-8839-87463613F216}
{66614C26-314C-4B91-9071-76133422CFEF} = {BFFB607F-7C78-434B-86B9-DA4C8196A1B5}
{66614C26-314C-4B91-9071-76133422CFEF} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
{3846508C-77EB-4034-A702-F8BB263C4F79} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{6CE438DF-C245-4997-A360-0A0939E4BA34} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
@@ -3104,6 +2983,8 @@ Global
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{605E914B-7232-4789-AF46-BF5D3DDFC14E} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE} = {9873BA05-4C41-4819-9283-CF45D795431B}
{7F5B9557-5878-4438-A721-3E28296BA193} = {9873BA05-4C41-4819-9283-CF45D795431B}
{DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{0A84F764-3A88-44CD-AA96-41BDBD48627B} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}
{E4585179-2AC1-4D5F-A3FF-CFC5392F694C} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}
@@ -3112,55 +2993,24 @@ Global
{A558C25D-2007-498E-8B6F-43405AFAE9E2} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{08F9155D-B6DC-46E5-9C83-AF60B655898B} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{4382A954-179A-4078-92AF-715187DFFF50} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{EBED240C-8702-452D-B764-6DB9DA9179AF} = {1C48CD47-D610-463A-A53C-AF82DD6C47E7}
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {1C48CD47-D610-463A-A53C-AF82DD6C47E7}
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {8131151D-B0E9-4E18-84A5-E5F946C4480A}
{EBED240C-8702-452D-B764-6DB9DA9179AF} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
{64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{0217E86E-3476-9946-DE8E-9D200CEBD47A} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E} = {66E1534A-1587-42B2-912F-45C994D32904}
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{9E0CBC06-F29A-4810-B93C-97D53863B95E} = {2F305555-C296-497E-AC20-5FA1B237996A}
{F6088A11-1C9E-4420-AA90-CF7E78DD7F1C} = {2F305555-C296-497E-AC20-5FA1B237996A}
{47B0678C-806B-4FE1-9F50-46BA88989532} = {2F305555-C296-497E-AC20-5FA1B237996A}
{9BC1C986-1E97-4D07-A7B1-CE226C239EFA} = {2F305555-C296-497E-AC20-5FA1B237996A}
{99CA1509-FB73-456E-AFAF-AB89C017BD72} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{61CBF221-9452-4934-B685-146285E080D7} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1} = {2C318EC3-BA86-4372-B1BC-DB0F33C208B2}
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9} = {68328142-5B31-4715-BCBB-7B6345EE0971}
{99CA1509-FB73-456E-AFAF-AB89C017BD72} = {2F305555-C296-497E-AC20-5FA1B237996A}
{61CBF221-9452-4934-B685-146285E080D7} = {2F305555-C296-497E-AC20-5FA1B237996A}
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{14AFD976-B4D2-49D0-9E6C-AA93CC061B8A} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{9D3F3793-EFE3-4525-8782-238015DABA62} = {66E1534A-1587-42B2-912F-45C994D32904}
{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{24133F7F-C1D1-DE04-EFA8-F5D5467FE027} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{0E556541-6A45-42CB-AE49-EE5A9BE05E7C} = {6C7F47CC-2151-44A3-A546-41C70025132C}
{27D9CB3A-46D1-402C-9273-F88CB8AC42F7} = {9873BA05-4C41-4819-9283-CF45D795431B}
{B9617A31-0F0A-4397-851D-BF2FBEE32D7F} = {C140A3EF-6DBF-4084-9D4C-4EB5A99FEE68}
{1C48CD47-D610-463A-A53C-AF82DD6C47E7} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{D9BD324E-1D80-44AA-8E7B-73EB00944434} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{8EF25507-2575-4ADE-BF7E-D23376903AB8} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{070AC093-C9F2-20AD-0BCD-F318FC2761EA} = {B1234567-1234-1234-1234-123456789ABC}
{2C318EC3-BA86-4372-B1BC-DB0F33C208B2} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{BFFB607F-7C78-434B-86B9-DA4C8196A1B5} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
{66E1534A-1587-42B2-912F-45C994D32904} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
{E885E71F-0B34-4A03-B13B-20F4E05E90BB} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
{264B412F-DB8B-4CF8-A74B-96998B183045} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
{3527BF37-DFC5-4309-A032-29278CA21328} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
{6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704} = {2F305555-C296-497E-AC20-5FA1B237996A}
{68328142-5B31-4715-BCBB-7B6345EE0971} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
{4122388B-59E4-CDB0-0338-EA6881DF86F0} = {27D9CB3A-46D1-402C-9273-F88CB8AC42F7}
{988C9FAF-5AEC-EB15-578D-FED0DF52BF55} = {27D9CB3A-46D1-402C-9273-F88CB8AC42F7}
{6748A29D-DA6A-033A-825B-752295FF6AA0} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{6EABCF9A-6526-441F-932F-658B1DC3E403} = {264B412F-DB8B-4CF8-A74B-96998B183045}
{69D76A76-6EF6-4846-94CD-EAAF0CAC9F15} = {264B412F-DB8B-4CF8-A74B-96998B183045}
{9BAFFC28-E1EF-4C14-A101-EEBFC0A50D83} = {264B412F-DB8B-4CF8-A74B-96998B183045}
{806BF185-8B89-5BE1-9AA1-DA5BC9487DB9} = {264B412F-DB8B-4CF8-A74B-96998B183045}
{F93C2817-C846-4259-84D8-B39A6B57C8DE} = {3527BF37-DFC5-4309-A032-29278CA21328}
{8131151D-B0E9-4E18-84A5-E5F946C4480A} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
{E816D7AC-4688-4ECB-97CC-3D8E798F3825} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7AD-4688-4ECB-97CC-3D8E798F3826} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7AE-4688-4ECB-97CC-3D8E798F3827} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7AF-4688-4ECB-97CC-3D8E798F3828} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{E816D7B0-4688-4ECB-97CC-3D8E798F3829} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{00D8659C-2068-40B6-8B86-759CD6284BBB} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{9D3F3793-EFE3-4525-8782-238015DABA62} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -22,23 +22,23 @@ The PowerToys UI test pipeline provides flexible options for building and testin
### Pipeline Options
- **buildSource**: Select the build type for testing:
- `latestMainOfficialBuild`: Downloads and uses the latest official PowerToys build from main branch
- `buildNow`: Builds PowerToys from current source code and uses it for testing
- `specificBuildId`: Downloads a specific PowerToys build using the build ID specified in `specificBuildId` parameter
- **useLatestOfficialBuild**: When checked, downloads the latest official PowerToys build and installs it for testing. This skips the full solution build and only builds UI test projects.
**Default value**: `latestMainOfficialBuild`
- **useCurrentBranchBuild**: When checked along with `useLatestOfficialBuild`, downloads the official build from the current branch instead of main.
- **specificBuildId**: When `buildSource` is set to `specificBuildId`, specify the exact PowerToys build ID to download and test against.
**Default value**: `"xxxx"` (placeholder, enter actual build ID when using specificBuildId option)
**Default value**: `false` (downloads from main branch)
**When to use this**:
- Testing against a specific known build for reproducibility
- Regression testing against a particular build version
- Validating fixes in a specific build before release
- **Default scenario**: The pipeline tests against the latest signed PowerToys build from the `main` branch, regardless of which branch your test code changes are from
- **Custom branch testing**: Only specify `true` when:
- Your branch has produced its own signed PowerToys build via the official build pipeline
- You want to test against that specific branch's PowerToys build instead of main
- You are testing PowerToys functionality changes that are only available in your branch's build
**Usage**: Enter the build ID number (e.g., `12345`) to download that specific build. Only used when `buildSource` is set to `specificBuildId`.
**Important notes**:
- The test pipeline itself runs from your specified branch, but by default tests against the main branch's PowerToys build
- Not all branches have signed builds available - only use this if you're certain your branch has a signed build
- If enabled but no build exists for your branch, the pipeline may fail or fall back to main
- **uiTestModules**: Specify which UI test modules to build and run. This parameter controls both the `.csproj` projects to build and the `.dll` test assemblies to execute. Examples:
- `['UITests-FancyZones']` - Only FancyZones UI tests
@@ -50,25 +50,25 @@ The PowerToys UI test pipeline provides flexible options for building and testin
### Build Modes
1. **Official Build Testing** (`buildSource = latestMainOfficialBuild` or `specificBuildId`)
- Downloads and installs official PowerToys build (latest from main or specific build ID)
- Builds only UI test projects (all or specific based on `uiTestModules`)
- Runs UI tests against installed PowerToys
- Tests both machine-level and per-user installation modes automatically
1. **Official Build + Selective Testing** (`useLatestOfficialBuild = true`)
- Downloads and installs official PowerToys build
- Builds only specified UI test projects
- Runs specified UI tests against installed PowerToys
- Controlled by `uiTestModules` parameter
2. **Current Source Build Testing** (`buildSource = buildNow`)
- Builds entire PowerToys solution from current source code
2. **Full Build + Testing** (`useLatestOfficialBuild = false`)
- Builds entire PowerToys solution
- Builds UI test projects (all or specific based on `uiTestModules`)
- Runs UI tests against freshly built PowerToys
- Uses artifacts from current pipeline build
- Runs UI tests (all or specific based on `uiTestModules`)
- Uses freshly built PowerToys for testing
> **Note**: All modes support the `uiTestModules` parameter to control which specific UI test modules to build and run. Both machine-level and per-user installation modes are tested automatically when using official builds.
> **Note**: Both modes support the `uiTestModules` parameter to control which specific UI test modules to build and run.
### Pipeline Access
- Pipeline: https://microsoft.visualstudio.com/Dart/_build?definitionId=161438&_a=summary
## How to add the first UI tests for your modules
- Follow the naming convention: ![{ModuleFolder}/Tests/{ModuleName}-{TestType(Fuzz/UI/Unit)}Tests](images/uitests/naming.png)
- Create a new project and add the following references to the project file. Change the OutputPath to your own module's path.
```
<Project Sdk="Microsoft.NET.Sdk">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -67,7 +67,10 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and an
- When you'd like the team to take a look (even if the work is not yet fully complete) mark the PR as 'Ready For Review' so that the team can review your work and provide comments, suggestions, and request changes. It may take several cycles, but the end result will be solid, testable, conformant code that is safe for us to merge.
- When the PR is approved, let the owner of the PR merge it. For community contributions, the reviewer who approved the PR can also merge it.
- Use the `Squash and merge` option to merge a PR. If you don't want to squash it because there are logically different commits, use `Rebase and merge`.
- Close issues automatically when referenced in a PR. You can use [closing keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) in the body of the PR to have GitHub automatically link your PR to the issue.
- We don't close issues automatically when referenced in a PR, so after the PR is merged:
- mark the issue(s) that the PR solved with the `Resolution-Fix-Committed` label, remove the `In progress` label and if the issue is assigned to a project, move the item to the `Done` status.
- don't close the issue if it's a bug in the current released version; since users tend to not search for closed issues, we will close the resolved issues when a new version is released.
- if it's not a code fix that effects the end user, the issue can be closed (for example a fix in the build or a code refactoring and so on).
## Compiling PowerToys

View File

@@ -47,9 +47,6 @@ Contact the developers of a plugin directly for assistance with a specific plugi
| [Weather](https://github.com/ruslanlap/PowerToysRun-Weather) | [ruslanlap](https://github.com/ruslanlap) | Get real-time weather information directly from PowerToys Run. |
| [Pomodoro](https://github.com/ruslanlap/PowerToysRun-Pomodoro) | [ruslanlap](https://github.com/ruslanlap) | Manage Pomodoro productivity sessions directly from PowerToys Run. |
| [Definition](https://github.com/ruslanlap/PowerToysRun-Definition) | [ruslanlap](https://github.com/ruslanlap) | Lookup word definitions, phonetics, and synonyms directly in PowerToys Run. |
| [Hotkeys](https://github.com/ruslanlap/PowerToysRun-Hotkeys) | [ruslanlap](https://github.com/ruslanlap) | Create, manage, and trigger custom keyboard shortcuts directly from PowerToys Run. |
| [RandomGen](https://github.com/ruslanlap/PowerToysRun-RandomGen) | [ruslanlap](https://github.com/ruslanlap) | 🎲 Generate random data instantly with a single keystroke. Perfect for developers, testers, designers, and anyone who needs quick access to random data. Features include secure passwords, PINs, names, business data, dates, numbers, GUIDs, color codes, and more. Especially useful for designers who need random color codes and placeholder content. |
| [Open With Cursor](https://github.com/VictorNoxx/PowerToys-Run-Cursor/) | [VictorNoxx](https://github.com/VictorNoxx) | Open Visual Studio, VS Code recents with Cursor AI |
## Extending software plugins

View File

@@ -2,10 +2,10 @@
<configuration>
<packageSources>
<clear />
<add key="PowerToysPublicDependencies" value="https://pkgs.dev.azure.com/shine-oss/PowerToys/_packaging/PowerToysPublicDependencies/nuget/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="PowerToysPublicDependencies">
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>

View File

@@ -7,7 +7,6 @@
<CsWinRTAotWarningLevel>2</CsWinRTAotWarningLevel>
<!-- Suppress DynamicallyAccessedMemberTypes.PublicParameterlessConstructor in fallback code path of Windows SDK projection -->
<!-- Suppress CA1416 for Windows-specific APIs that are used in PowerToys which only runs on Windows 10.0.19041.0+ -->
<WarningsNotAsErrors>IL2081;CsWinRT1028;CA1416;$(WarningsNotAsErrors)</WarningsNotAsErrors>
<WarningsNotAsErrors>IL2081;CsWinRT1028;$(WarningsNotAsErrors)</WarningsNotAsErrors>
</PropertyGroup>
</Project>

View File

@@ -24,16 +24,5 @@ namespace Microsoft.PowerToys.UITest
{
this.Find<NavigationViewItem>(value).Click();
}
/// <summary>
/// Select a text item from the ComboBox.
/// </summary>
/// <param name="value">The text to select from the ComboBox.</param>
public void SelectTxt(string value)
{
this.Click(); // First click to expand the ComboBox
Thread.Sleep(100); // Wait for the dropdown to appear
this.Find<Element>(value).Click(); // Find and click the text item using basic Element type
}
}
}

View File

@@ -364,7 +364,7 @@ namespace Microsoft.PowerToys.UITest
/// Save UI Element to a PNG file.
/// </summary>
/// <param name="path">the full path</param>
public void SaveToPngFile(string path)
internal void SaveToPngFile(string path)
{
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method SaveToPngFile with parameter: path = {path}");
this.windowsElement.GetScreenshot().SaveAsFile(path);

View File

@@ -1,38 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Represents a radio button UI element in the application.
/// </summary>
public class RadioButton : Element
{
private static readonly string ExpectedControlType = "ControlType.RadioButton";
/// <summary>
/// Initializes a new instance of the <see cref="RadioButton"/> class.
/// </summary>
public RadioButton()
{
this.TargetControlType = RadioButton.ExpectedControlType;
}
/// <summary>
/// Gets a value indicating whether the RadioButton is selected.
/// </summary>
public bool IsSelected => this.Selected;
/// <summary>
/// Select the RadioButton.
/// </summary>
public void Select()
{
if (!this.IsSelected)
{
this.Click();
}
}
}
}

View File

@@ -2,8 +2,6 @@
// 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.Threading.Tasks;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
@@ -27,9 +25,8 @@ namespace Microsoft.PowerToys.UITest
/// </summary>
/// <param name="value">The text to set.</param>
/// <param name="clearText">A value indicating whether to clear the text before setting it. Default value is true</param>
/// <param name="charDelayMS">Delay in milliseconds between each character. Default is 0 (no delay).</param>
/// <returns>The current TextBox instance.</returns>
public TextBox SetText(string value, bool clearText = true, int charDelayMS = 0)
public TextBox SetText(string value, bool clearText = true)
{
if (clearText)
{
@@ -42,36 +39,10 @@ namespace Microsoft.PowerToys.UITest
Task.Delay(500).Wait();
}
// TODO: CmdPal bug when inputting text, characters are swallowed too quickly.
// This should be fixed within CmdPal itself.
// Temporary workaround: introduce a delay between character inputs to avoid the issue
if (charDelayMS > 0 || EnvironmentConfig.IsInPipeline)
PerformAction((actions, windowElement) =>
{
// Send text character by character with delay (if specified or in pipeline)
PerformAction((actions, windowElement) =>
{
foreach (char c in value)
{
windowElement.SendKeys(c.ToString());
if (charDelayMS > 0)
{
Task.Delay(charDelayMS).Wait();
}
else if (EnvironmentConfig.IsInPipeline)
{
Task.Delay(50).Wait();
}
}
});
}
else
{
// No character delay - send all text at once (original behavior)
PerformAction((actions, windowElement) =>
{
windowElement.SendKeys(value);
});
}
windowElement.SendKeys(value);
});
return this;
}

View File

@@ -1,45 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.PowerToys.UITest
{
/// <summary>
/// Centralized configuration for all environment variables used in UI tests.
/// </summary>
public static class EnvironmentConfig
{
private static readonly Lazy<bool> _isInPipeline = new(() =>
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("platform")));
private static readonly Lazy<bool> _useInstallerForTest = new(() =>
{
string? envValue = Environment.GetEnvironmentVariable("useInstallerForTest") ??
Environment.GetEnvironmentVariable("USEINSTALLERFORTEST");
return !string.IsNullOrEmpty(envValue) && bool.TryParse(envValue, out bool result) && result;
});
private static readonly Lazy<string?> _platform = new(() =>
Environment.GetEnvironmentVariable("platform"));
/// <summary>
/// Gets a value indicating whether the tests are running in a CI/CD pipeline.
/// Determined by the presence of the "platform" environment variable.
/// </summary>
public static bool IsInPipeline => _isInPipeline.Value;
/// <summary>
/// Gets a value indicating whether to use installer paths for testing.
/// Checks both "useInstallerForTest" and "USEINSTALLERFORTEST" environment variables.
/// </summary>
public static bool UseInstallerForTest => _useInstallerForTest.Value;
/// <summary>
/// Gets the platform name from the environment variable.
/// Typically used in CI/CD pipelines to identify the build platform.
/// </summary>
public static string? Platform => _platform.Value;
}
}

View File

@@ -32,7 +32,6 @@ namespace Microsoft.PowerToys.UITest
Runner,
Workspaces,
PowerRename,
CommandPalette,
}
/// <summary>
@@ -92,7 +91,9 @@ namespace Microsoft.PowerToys.UITest
private ModuleConfigData()
{
// Check if we should use installer paths from environment variable
UseInstallerForTest = EnvironmentConfig.UseInstallerForTest;
string? useInstallerForTestEnv =
Environment.GetEnvironmentVariable("useInstallerForTest") ?? Environment.GetEnvironmentVariable("USEINSTALLERFORTEST");
UseInstallerForTest = !string.IsNullOrEmpty(useInstallerForTestEnv) && bool.TryParse(useInstallerForTestEnv, out bool result) && result;
// Module information including executable name, window name, and optional subdirectory
ModuleInfo = new Dictionary<PowerToysModule, ModuleInfo>
@@ -103,7 +104,6 @@ namespace Microsoft.PowerToys.UITest
[PowerToysModule.Runner] = new ModuleInfo("PowerToys.exe", "PowerToys"),
[PowerToysModule.Workspaces] = new ModuleInfo("PowerToys.WorkspacesEditor.exe", "Workspaces Editor"),
[PowerToysModule.PowerRename] = new ModuleInfo("PowerToys.PowerRename.exe", "PowerRename", "WinUI3Apps"),
[PowerToysModule.CommandPalette] = new ModuleInfo("Microsoft.CmdPal.UI.exe", "PowerToys Command Palette", "WinUI3Apps\\CmdPal"),
};
}

View File

@@ -5,7 +5,6 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@@ -38,9 +37,6 @@ namespace Microsoft.PowerToys.UITest
private PowerToysModule scope;
private string[]? commandLineArgs;
/// <summary>
/// Gets a value indicating whether to use installer paths for testing.
/// </summary>
private bool UseInstallerForTest { get; }
[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "<Pending>")]
@@ -49,7 +45,9 @@ namespace Microsoft.PowerToys.UITest
this.scope = scope;
this.commandLineArgs = commandLineArgs;
this.sessionPath = ModuleConfigData.Instance.GetModulePath(scope);
UseInstallerForTest = EnvironmentConfig.UseInstallerForTest;
string? useInstallerForTestEnv =
Environment.GetEnvironmentVariable("useInstallerForTest") ?? Environment.GetEnvironmentVariable("USEINSTALLERFORTEST");
UseInstallerForTest = !string.IsNullOrEmpty(useInstallerForTestEnv) && bool.TryParse(useInstallerForTestEnv, out bool result) && result;
this.locationPath = UseInstallerForTest ? string.Empty : Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
CheckWinAppDriverAndRoot();
@@ -93,12 +91,15 @@ namespace Microsoft.PowerToys.UITest
}
/// <summary>
/// Exit a exe by Name.
/// Exit a exe.
/// </summary>
/// <param name="processName">The path to the application executable.</param>
public void ExitExeByName(string processName)
/// <param name="appPath">The path to the application executable.</param>
public void ExitExe(string appPath)
{
Process[] processes = Process.GetProcessesByName(processName);
// Exit Exe
string exeName = Path.GetFileNameWithoutExtension(appPath);
Process[] processes = Process.GetProcessesByName(exeName);
foreach (Process process in processes)
{
try
@@ -113,18 +114,6 @@ namespace Microsoft.PowerToys.UITest
}
}
/// <summary>
/// Exit a exe.
/// </summary>
/// <param name="appPath">The path to the application executable.</param>
public void ExitExe(string appPath)
{
// Exit Exe
string exeName = Path.GetFileNameWithoutExtension(appPath);
ExitExeByName(exeName);
}
/// <summary>
/// Starts a new exe and takes control of it.
/// </summary>
@@ -133,113 +122,69 @@ namespace Microsoft.PowerToys.UITest
public void StartExe(string appPath, string[]? args = null)
{
var opts = new AppiumOptions();
opts.AddAdditionalCapability("app", appPath);
if (scope == PowerToysModule.PowerToysSettings)
if (args != null && args.Length > 0)
{
TryLaunchPowerToysSettings(opts);
}
else if (scope == PowerToysModule.CommandPalette && UseInstallerForTest)
{
TryLaunchCommandPalette(opts);
}
else
{
opts.AddAdditionalCapability("app", appPath);
if (args != null && args.Length > 0)
// Build command line arguments string
string argsString = string.Join(" ", args.Select(arg =>
{
// Build command line arguments string
string argsString = string.Join(" ", args.Select(arg =>
// Quote arguments that contain spaces
if (arg.Contains(' '))
{
// Quote arguments that contain spaces
if (arg.Contains(' '))
{
return $"\"{arg}\"";
}
return $"\"{arg}\"";
}
return arg;
}));
return arg;
}));
opts.AddAdditionalCapability("appArguments", argsString);
}
opts.AddAdditionalCapability("appArguments", argsString);
}
Driver = NewWindowsDriver(opts);
this.Driver = NewWindowsDriver(opts);
}
private void TryLaunchPowerToysSettings(AppiumOptions opts)
{
try
CheckWinAppDriverAndRoot();
var runnerProcessInfo = new ProcessStartInfo
{
var runnerProcessInfo = new ProcessStartInfo
{
FileName = locationPath + runnerPath,
Verb = "runas",
Arguments = "--open-settings",
};
FileName = locationPath + this.runnerPath,
Verb = "runas",
Arguments = "--open-settings",
};
ExitExe(runnerProcessInfo.FileName);
runner = Process.Start(runnerProcessInfo);
this.ExitExe(runnerProcessInfo.FileName);
this.runner = Process.Start(runnerProcessInfo);
Thread.Sleep(5000);
WaitForWindowAndSetCapability(opts, "PowerToys Settings", 5000, 5);
// Exit CmdPal UI before launching new process if use installer for test
ExitExeByName("Microsoft.CmdPal.UI");
}
catch (Exception ex)
if (root != null)
{
throw new InvalidOperationException($"Failed to launch PowerToys Settings: {ex.Message}", ex);
}
}
const int maxRetries = 5;
const int delayMs = 5000;
var windowName = "PowerToys Settings";
private void TryLaunchCommandPalette(AppiumOptions opts)
{
try
{
// Exit any existing CmdPal UI process
ExitExeByName("Microsoft.CmdPal.UI");
var processStartInfo = new ProcessStartInfo
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
FileName = "cmd.exe",
Arguments = "/c start shell:appsFolder\\Microsoft.CommandPalette_8wekyb3d8bbwe!App",
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
};
var settingsWindow = ApiHelper.FindDesktopWindowHandler(
new[] { windowName, AdministratorPrefix + windowName });
var process = Process.Start(processStartInfo);
process?.WaitForExit();
if (settingsWindow.Count > 0)
{
var hexHwnd = settingsWindow[0].HWnd.ToString("x");
opts.AddAdditionalCapability("appTopLevelWindow", hexHwnd);
return;
}
WaitForWindowAndSetCapability(opts, "Command Palette", 5000, 10);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to launch Command Palette: {ex.Message}", ex);
}
}
private void WaitForWindowAndSetCapability(AppiumOptions opts, string windowName, int delayMs, int maxRetries)
{
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
var window = ApiHelper.FindDesktopWindowHandler(
[windowName, AdministratorPrefix + windowName]);
if (window.Count > 0)
{
var hexHwnd = window[0].HWnd.ToString("x");
opts.AddAdditionalCapability("appTopLevelWindow", hexHwnd);
return;
}
if (attempt < maxRetries)
{
Thread.Sleep(delayMs);
}
else
{
throw new TimeoutException($"Failed to find {windowName} window after multiple attempts.");
if (attempt < maxRetries)
{
Thread.Sleep(delayMs);
}
else
{
throw new TimeoutException("Failed to find PowerToys Settings window after multiple attempts.");
}
}
}
}

View File

@@ -20,7 +20,6 @@
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.RegularExpressions" />
<PackageReference Include="CoenM.ImageSharp.ImageHash" />
</ItemGroup>
</Project>

View File

@@ -5,7 +5,6 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
@@ -21,13 +20,8 @@ namespace Microsoft.PowerToys.UITest
public required Session Session { get; set; }
/// <summary>
/// Gets a value indicating whether the tests are running in a CI/CD pipeline.
/// </summary>
public bool IsInPipeline { get; }
public string? ScreenshotDirectory { get; set; }
public static MonitorInfoData.ParamsWrapper MonitorInfoData { get; set; } = new MonitorInfoData.ParamsWrapper() { Monitors = new List<MonitorInfoData.MonitorInfoDataWrapper>() };
private readonly PowerToysModule scope;
@@ -35,11 +29,12 @@ namespace Microsoft.PowerToys.UITest
private readonly string[]? commandLineArgs;
private SessionHelper? sessionHelper;
private System.Threading.Timer? screenshotTimer;
private string? screenshotDirectory;
public UITestBase(PowerToysModule scope = PowerToysModule.PowerToysSettings, WindowSize size = WindowSize.UnSpecified, string[]? commandLineArgs = null)
{
this.IsInPipeline = EnvironmentConfig.IsInPipeline;
Console.WriteLine($"Running tests on platform: {EnvironmentConfig.Platform}");
this.IsInPipeline = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("platform"));
Console.WriteLine($"Running tests on platform: {Environment.GetEnvironmentVariable("platform")}");
if (IsInPipeline)
{
NativeMethods.ChangeDisplayResolution(1920, 1080);
@@ -60,15 +55,14 @@ namespace Microsoft.PowerToys.UITest
[TestInitialize]
public void TestInit()
{
KeyboardHelper.SendKeys(Key.Win, Key.M);
CloseOtherApplications();
if (IsInPipeline)
{
ScreenshotDirectory = Path.Combine(this.TestContext.TestResultsDirectory ?? string.Empty, "UITestScreenshots_" + Guid.NewGuid().ToString());
Directory.CreateDirectory(ScreenshotDirectory);
screenshotDirectory = Path.Combine(this.TestContext.TestResultsDirectory ?? string.Empty, "UITestScreenshots_" + Guid.NewGuid().ToString());
Directory.CreateDirectory(screenshotDirectory);
// Take screenshot every 1 second
screenshotTimer = new System.Threading.Timer(ScreenCapture.TimerCallback, ScreenshotDirectory, TimeSpan.Zero, TimeSpan.FromMilliseconds(1000));
screenshotTimer = new System.Threading.Timer(ScreenCapture.TimerCallback, screenshotDirectory, TimeSpan.Zero, TimeSpan.FromMilliseconds(1000));
// Escape Popups before starting
System.Windows.Forms.SendKeys.SendWait("{ESC}");
@@ -252,174 +246,6 @@ namespace Microsoft.PowerToys.UITest
return this.Session.Has<Element>(name, timeoutMS, global);
}
/// <summary>
/// Finds an element using partial name matching (contains).
/// Useful for finding windows with variable titles like "filename.txt - Notepad" or "filename - Notepad".
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="partialName">Part of the name to search for.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found element.</returns>
protected T FindByPartialName<T>(string partialName, int timeoutMS = 5000, bool global = false)
where T : Element, new()
{
return Session.Find<T>(By.XPath($"//*[contains(@Name, '{partialName}')]"), timeoutMS, global);
}
/// <summary>
/// Finds an element using partial name matching (contains).
/// </summary>
/// <param name="partialName">Part of the name to search for.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found element.</returns>
protected Element FindByPartialName(string partialName, int timeoutMS = 5000, bool global = false)
{
return FindByPartialName<Element>(partialName, timeoutMS, global);
}
/// <summary>
/// Base method for finding elements by selector and filtering by name pattern.
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="selector">The selector to find initial candidates.</param>
/// <param name="namePattern">Pattern to match against the Name attribute. Supports regex patterns.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <param name="errorMessage">Custom error message when no element is found.</param>
/// <returns>The found element.</returns>
private T FindByNamePattern<T>(By selector, string namePattern, int timeoutMS = 5000, bool global = false, string? errorMessage = null)
where T : Element, new()
{
var elements = Session.FindAll<T>(selector, timeoutMS, global);
var regex = new Regex(namePattern, RegexOptions.IgnoreCase);
foreach (var element in elements)
{
var name = element.GetAttribute("Name");
if (!string.IsNullOrEmpty(name) && regex.IsMatch(name))
{
return element;
}
}
throw new NoSuchElementException(errorMessage ?? $"No element found matching pattern: {namePattern}");
}
/// <summary>
/// Finds an element using regular expression pattern matching.
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="pattern">Regular expression pattern to match against the Name attribute.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found element.</returns>
protected T FindByPattern<T>(string pattern, int timeoutMS = 5000, bool global = false)
where T : Element, new()
{
return FindByNamePattern<T>(By.XPath("//*[@Name]"), pattern, timeoutMS, global, $"No element found matching pattern: {pattern}");
}
/// <summary>
/// Finds an element using regular expression pattern matching.
/// </summary>
/// <param name="pattern">Regular expression pattern to match against the Name attribute.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found element.</returns>
protected Element FindByPattern(string pattern, int timeoutMS = 5000, bool global = false)
{
return FindByPattern<Element>(pattern, timeoutMS, global);
}
/// <summary>
/// Finds an element by ClassName only.
/// Returns the first element found with the specified ClassName.
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="className">The ClassName to search for (e.g., "Notepad", "CabinetWClass").</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found element.</returns>
protected T FindByClassName<T>(string className, int timeoutMS = 5000, bool global = false)
where T : Element, new()
{
return Session.Find<T>(By.ClassName(className), timeoutMS, global);
}
/// <summary>
/// Finds an element by ClassName only.
/// Returns the first element found with the specified ClassName.
/// </summary>
/// <param name="className">The ClassName to search for (e.g., "Notepad", "CabinetWClass").</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found element.</returns>
protected Element FindByClassName(string className, int timeoutMS = 5000, bool global = false)
{
return FindByClassName<Element>(className, timeoutMS, global);
}
/// <summary>
/// Finds an element by ClassName and matches its Name attribute using regex pattern matching.
/// </summary>
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
/// <param name="className">The ClassName to search for (e.g., "Notepad", "CabinetWClass").</param>
/// <param name="namePattern">Pattern to match against the Name attribute. Supports regex patterns.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found element.</returns>
protected T FindByClassNameAndNamePattern<T>(string className, string namePattern, int timeoutMS = 5000, bool global = false)
where T : Element, new()
{
return FindByNamePattern<T>(By.ClassName(className), namePattern, timeoutMS, global, $"No element with ClassName '{className}' found matching name pattern: {namePattern}");
}
/// <summary>
/// Finds an element by ClassName and matches its Name attribute using regex pattern matching.
/// </summary>
/// <param name="className">The ClassName to search for (e.g., "Notepad", "CabinetWClass").</param>
/// <param name="namePattern">Pattern to match against the Name attribute. Supports regex patterns.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found element.</returns>
protected Element FindByClassNameAndNamePattern(string className, string namePattern, int timeoutMS = 5000, bool global = false)
{
return FindByClassNameAndNamePattern<Element>(className, namePattern, timeoutMS, global);
}
/// <summary>
/// Finds a Notepad window regardless of whether the file extension is shown in the title.
/// Handles both "filename.txt - Notepad" and "filename - Notepad" formats.
/// Uses ClassName to efficiently find Notepad windows first, then matches the filename.
/// </summary>
/// <param name="baseFileName">The base filename without extension (e.g., "test" for "test.txt").</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found Notepad window element.</returns>
protected Element FindNotepadWindow(string baseFileName, int timeoutMS = 5000, bool global = false)
{
string pattern = $@"^{Regex.Escape(baseFileName)}(\.\w+)?(\s*-\s*|\s+)Notepad$";
return FindByClassNameAndNamePattern("Notepad", pattern, timeoutMS, global);
}
/// <summary>
/// Finds an Explorer window regardless of the folder or file name display format.
/// Handles various Explorer window title formats like "FolderName", "FileName", "FolderName - File Explorer", etc.
/// Uses ClassName to efficiently find Explorer windows first, then matches the folder or file name.
/// </summary>
/// <param name="folderName">The folder or file name to search for (e.g., "Documents", "Desktop", "test.txt").</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found Explorer window element.</returns>
protected Element FindExplorerWindow(string folderName, int timeoutMS = 5000, bool global = false)
{
string pattern = $@"^{Regex.Escape(folderName)}(\s*-\s*(File\s+Explorer|Windows\s+Explorer))?$";
return FindByClassNameAndNamePattern("CabinetWClass", pattern, timeoutMS, global);
}
/// <summary>
/// Finds an Explorer window by partial folder path.
/// Useful when the full path might be displayed in the title.
/// </summary>
/// <param name="partialPath">Part of the folder path to search for.</param>
/// <param name="timeoutMS">The timeout in milliseconds (default is 5000).</param>
/// <returns>The found Explorer window element.</returns>
protected Element FindExplorerByPartialPath(string partialPath, int timeoutMS = 5000, bool global = false)
{
return FindByPartialName(partialPath, timeoutMS, global);
}
/// <summary>
/// Finds all elements by selector.
/// Shortcut for this.Session.FindAll<T>(by, timeoutMS)
@@ -589,9 +415,9 @@ namespace Microsoft.PowerToys.UITest
protected void AddScreenShotsToTestResultsDirectory()
{
if (ScreenshotDirectory != null)
if (screenshotDirectory != null)
{
foreach (string file in Directory.GetFiles(ScreenshotDirectory))
foreach (string file in Directory.GetFiles(screenshotDirectory))
{
this.TestContext.AddResultFile(file);
}
@@ -801,23 +627,6 @@ namespace Microsoft.PowerToys.UITest
Console.WriteLine($"Failed to change display resolution. Error code: {result}");
}
}
// Windows API for moving windows
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
private const uint SWPNOSIZE = 0x0001;
private const uint SWPNOZORDER = 0x0004;
public static void MoveWindow(Element window, int x, int y)
{
var windowHandle = IntPtr.Parse(window.GetAttribute("NativeWindowHandle") ?? "0", System.Globalization.CultureInfo.InvariantCulture);
if (windowHandle != IntPtr.Zero)
{
SetWindowPos(windowHandle, IntPtr.Zero, x, y, 0, 0, SWPNOSIZE | SWPNOZORDER);
Task.Delay(500).Wait();
}
}
}
}
}

View File

@@ -6,11 +6,7 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.IO;
using CoenM.ImageHash;
using CoenM.ImageHash.HashAlgorithms;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
namespace Microsoft.PowerToys.UITest
{
@@ -27,8 +23,10 @@ namespace Microsoft.PowerToys.UITest
[RequiresUnreferencedCode("This method uses reflection which may not be compatible with trimming.")]
public static void AreEqual(TestContext? testContext, Element element, string scenarioSubname = "")
{
var pipelinePlatform = Environment.GetEnvironmentVariable("platform");
// Perform visual validation only in the pipeline
if (!EnvironmentConfig.IsInPipeline)
if (string.IsNullOrEmpty(pipelinePlatform))
{
Console.WriteLine("Skip visual validation in the local run.");
return;
@@ -53,11 +51,11 @@ namespace Microsoft.PowerToys.UITest
if (string.IsNullOrWhiteSpace(scenarioSubname))
{
scenarioSubname = string.Join("_", callerClassName, callerName, EnvironmentConfig.Platform);
scenarioSubname = string.Join("_", callerClassName, callerName, pipelinePlatform);
}
else
{
scenarioSubname = string.Join("_", callerClassName, callerName, scenarioSubname.Trim(), EnvironmentConfig.Platform);
scenarioSubname = string.Join("_", callerClassName, callerName, scenarioSubname.Trim(), pipelinePlatform);
}
var baselineImageResourceName = callerMethod!.DeclaringType!.Assembly.GetManifestResourceNames().Where(name => name.Contains(scenarioSubname)).FirstOrDefault();
@@ -129,75 +127,34 @@ namespace Microsoft.PowerToys.UITest
}
/// <summary>
/// Test if two images are equal using ImageHash comparison
/// Test if two images are equal bit-by-bit
/// </summary>
/// <param name="baselineImage">baseline image</param>
/// <param name="testImage">test image</param>
/// <returns>true if are equal,otherwise false</returns>
private static bool AreEqual(Bitmap baselineImage, Bitmap testImage)
{
try
if (baselineImage.Width != testImage.Width || baselineImage.Height != testImage.Height)
{
// Define a threshold for similarity percentage
const int SimilarityThreshold = 95;
// Use CoenM.ImageHash for perceptual hash comparison
var hashAlgorithm = new AverageHash();
// Convert System.Drawing.Bitmap to SixLabors.ImageSharp.Image
using var baselineImageSharp = ConvertBitmapToImageSharp(baselineImage);
using var testImageSharp = ConvertBitmapToImageSharp(testImage);
// Calculate hashes for both images
var baselineHash = hashAlgorithm.Hash(baselineImageSharp);
var testHash = hashAlgorithm.Hash(testImageSharp);
// Compare hashes using CompareHash method
// Returns similarity percentage (0-100, where 100 is identical)
var similarity = CompareHash.Similarity(baselineHash, testHash);
// Consider images equal if similarity is very high
// Allow for minor rendering differences (threshold can be adjusted)
return similarity >= SimilarityThreshold; // 95% similarity threshold
return false;
}
catch
// WinAppDriver sometimes adds a border to the screenshot (around 2 pix width), and it is not always consistent.
// So we exclude the border when comparing the images, and usually it is the edge of the windows, won't affect the comparison.
int excludeBorderWidth = 5, excludeBorderHeight = 5;
for (int x = excludeBorderWidth; x < baselineImage.Width - excludeBorderWidth; x++)
{
// Fallback to pixel-by-pixel comparison if hash comparison fails
if (baselineImage.Width != testImage.Width || baselineImage.Height != testImage.Height)
for (int y = excludeBorderHeight; y < baselineImage.Height - excludeBorderHeight; y++)
{
return false;
}
// WinAppDriver sometimes adds a border to the screenshot (around 2 pix width), and it is not always consistent.
// So we exclude the border when comparing the images, and usually it is the edge of the windows, won't affect the comparison.
int excludeBorderWidth = 5, excludeBorderHeight = 5;
for (int x = excludeBorderWidth; x < baselineImage.Width - excludeBorderWidth; x++)
{
for (int y = excludeBorderHeight; y < baselineImage.Height - excludeBorderHeight; y++)
if (!VisualHelper.PixIsSame(baselineImage.GetPixel(x, y), testImage.GetPixel(x, y)))
{
if (!VisualHelper.PixIsSame(baselineImage.GetPixel(x, y), testImage.GetPixel(x, y)))
{
return false;
}
return false;
}
}
return true;
}
}
/// <summary>
/// Convert System.Drawing.Bitmap to SixLabors.ImageSharp.Image
/// </summary>
/// <param name="bitmap">The bitmap to convert</param>
/// <returns>ImageSharp Image</returns>
private static Image<Rgba32> ConvertBitmapToImageSharp(Bitmap bitmap)
{
using var memoryStream = new MemoryStream();
bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
memoryStream.Position = 0;
return SixLabors.ImageSharp.Image.Load<Rgba32>(memoryStream);
return true;
}
}
}

View File

@@ -7,7 +7,6 @@
<Keyword>Win32Proj</Keyword>
<RootNamespace>UnitTestsCommonLib</RootNamespace>
<ProjectSubType>NativeUnitTestProject</ProjectSubType>
<ProjectName>Common.Lib.UnitTests</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">

View File

@@ -1,38 +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>
<ProjectGuid>{2B1505FA-132A-460B-B22B-7CC3FFAB0C5D}</ProjectGuid>
<RootNamespace>Microsoft.AdvancedPaste.UITests</RootNamespace>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<OutputType>Library</OutputType>
<!-- This is a UI test, so don't run as part of MSBuild -->
<RunVSTest>false</RunVSTest>
</PropertyGroup>
<PropertyGroup>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\tests\UITests-AdvancedPaste\</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Appium.WebDriver" />
<PackageReference Include="MSTest" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Private.Uri" />
<PackageReference Include="System.Text.RegularExpressions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\UITestAutomation\UITestAutomation.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="TestFiles\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -1,791 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using Microsoft.AdvancedPaste.UITests.Helper;
using Microsoft.CodeCoverage.Core.Reports.Coverage;
using Microsoft.PowerToys.UITest;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using Windows.ApplicationModel.DataTransfer;
using static System.Net.Mime.MediaTypeNames;
using static System.Resources.ResXFileRef;
using static System.Runtime.InteropServices.JavaScript.JSType;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip;
namespace Microsoft.AdvancedPaste.UITests
{
[TestClass]
public class AdvancedPasteUITest : UITestBase
{
private readonly string testFilesFolderPath;
private readonly string tempRTFFileName = "TempFile.rtf";
private readonly string pasteAsPlainTextRawFileName = "PasteAsPlainTextFileRaw.rtf";
private readonly string pasteAsPlainTextPlainFileName = "PasteAsPlainTextFilePlain.rtf";
private readonly string pasteAsPlainTextPlainNoRepeatFileName = "PasteAsPlainTextFilePlainNoRepeat.rtf";
private readonly string wordpadPath = @"C:\Program Files\wordpad\wordpad.exe";
private readonly string tempTxtFileName = "TempFile.txt";
private readonly string pasteAsMarkdownSrcFile = "PasteAsMarkdownFile.html";
private readonly string pasteAsMarkdownResultFile = "PasteAsMarkdownResultFile.txt";
private readonly string pasteAsJsonFileName = "PasteAsJsonFile.xml";
private readonly string pasteAsJsonResultFile = "PasteAsJsonResultFile.txt";
private bool _notepadSettingsChanged;
// Static constructor - runs before any instance is created
static AdvancedPasteUITest()
{
// Using the predefined settings.
// paste as plain text: win + ctrl + alt + o
// paste as markdown text: win + ctrl + alt + m
// paste as json text: win + ctrl + alt + j
CopySettingsFileBeforeTests();
}
public AdvancedPasteUITest()
: base(PowerToysModule.PowerToysSettings, size: WindowSize.Small)
{
Type currentTestType = typeof(AdvancedPasteUITest);
string? dirName = Path.GetDirectoryName(currentTestType.Assembly.Location);
Assert.IsNotNull(dirName, "Failed to get directory name of the current test assembly.");
string testFilesFolder = Path.Combine(dirName, "TestFiles");
Assert.IsTrue(Directory.Exists(testFilesFolder), $"Test files directory not found at: {testFilesFolder}");
testFilesFolderPath = testFilesFolder;
// ignore the notepad settings in pipeline
_notepadSettingsChanged = true;
}
[TestInitialize]
public void TestInitialize()
{
Session.CloseMainWindow();
SendKeys(Key.Win, Key.M);
}
[TestMethod]
[TestCategory("AdvancedPasteUITest")]
[TestCategory("PasteAsPlainText")]
[Ignore("Temporarily disabled due to wordpad.exe is missing in pipeline.")]
public void TestCasePasteAsPlainText()
{
// Copy some rich text(e.g word of the text is different color, another work is bold, underlined, etd.).
// Paste the text using standard Windows Ctrl + V shortcut and ensure that rich text is pasted(with all colors, formatting, etc.)
DeleteAndCopyFile(pasteAsPlainTextRawFileName, tempRTFFileName);
ContentCopyAndPasteDirectly(tempRTFFileName, isRTF: true);
var resultWithFormatting = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempRTFFileName),
Path.Combine(testFilesFolderPath, pasteAsPlainTextRawFileName),
compareFormatting: true);
Assert.IsTrue(resultWithFormatting.IsConsistent, "RTF files should be identical including formatting");
// Paste the text using Paste As Plain Text activation shortcut and ensure that plain text without any formatting is pasted.
// Paste again the text using standard Windows Ctrl + V shortcut and ensure the text is now pasted plain without formatting as well.
DeleteAndCopyFile(pasteAsPlainTextRawFileName, tempRTFFileName);
ContentCopyAndPasteWithShortcutThenPasteAgain(tempRTFFileName, isRTF: true);
resultWithFormatting = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempRTFFileName),
Path.Combine(testFilesFolderPath, pasteAsPlainTextPlainFileName),
compareFormatting: true);
Assert.IsTrue(resultWithFormatting.IsConsistent, "RTF files should be identical without formatting");
// Copy some rich text again.
// Open Advanced Paste window using hotkey, click Paste as Plain Text button and confirm that plain text without any formatting is pasted.
DeleteAndCopyFile(pasteAsPlainTextRawFileName, tempRTFFileName);
ContentCopyAndPasteCase3(tempRTFFileName, isRTF: true);
resultWithFormatting = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempRTFFileName),
Path.Combine(testFilesFolderPath, pasteAsPlainTextPlainNoRepeatFileName),
compareFormatting: true);
Assert.IsTrue(resultWithFormatting.IsConsistent, "RTF files should be identical without formatting");
// Copy some rich text again.
// Open Advanced Paste window using hotkey, press Ctrl + 1 and confirm that plain text without any formatting is pasted.
DeleteAndCopyFile(pasteAsPlainTextRawFileName, tempRTFFileName);
ContentCopyAndPasteCase4(tempRTFFileName, isRTF: true);
resultWithFormatting = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempRTFFileName),
Path.Combine(testFilesFolderPath, pasteAsPlainTextPlainNoRepeatFileName),
compareFormatting: true);
Assert.IsTrue(resultWithFormatting.IsConsistent, "RTF files should be identical without formatting");
}
[TestMethod]
[TestCategory("AdvancedPasteUITest")]
[TestCategory("PasteAsMarkdownCase1")]
public void TestCasePasteAsMarkdownCase1()
{
if (_notepadSettingsChanged == false)
{
ChangeNotePadSettings();
}
// Copy some text(e.g.some HTML text - convertible to Markdown)
// Paste the text using set hotkey and confirm that pasted text is converted to markdown
DeleteAndCopyFile(pasteAsMarkdownSrcFile, tempTxtFileName);
ContentCopyAndPasteAsMarkdownCase1(tempTxtFileName);
var result = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempTxtFileName),
Path.Combine(testFilesFolderPath, pasteAsMarkdownResultFile),
compareFormatting: true);
Assert.IsTrue(result.IsConsistent, "Paste as markdown using shortcut failed.");
}
[TestMethod]
[TestCategory("AdvancedPasteUITest")]
[TestCategory("PasteAsMarkdownCase2")]
public void TestCasePasteAsMarkdownCase2()
{
if (_notepadSettingsChanged == false)
{
ChangeNotePadSettings();
}
// Copy some text(same as in the previous step or different.If nothing is coppied between steps, previously pasted Markdown text will be picked up from clipboard and converted again to nested Markdown).
// Open Advanced Paste window using hotkey, click Paste as markdown button and confirm that pasted text is converted to markdown
DeleteAndCopyFile(pasteAsMarkdownSrcFile, tempTxtFileName);
ContentCopyAndPasteAsMarkdownCase2(tempTxtFileName);
var result = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempTxtFileName),
Path.Combine(testFilesFolderPath, pasteAsMarkdownResultFile),
compareFormatting: true);
Assert.IsTrue(result.IsConsistent, "Paste as markdown using shortcut failed.");
}
[TestMethod]
[TestCategory("AdvancedPasteUITest")]
[TestCategory("PasteAsMarkdownCase3")]
public void TestCasePasteAsMarkdownCase3()
{
if (_notepadSettingsChanged == false)
{
ChangeNotePadSettings();
}
// Copy some text(same as in the previous step or different.If nothing is coppied between steps, previously pasted Markdown text will be picked up from clipboard and converted again to nested Markdown).
// Open Advanced Paste window using hotkey, press Ctrl + 2 and confirm that pasted text is converted to markdown
DeleteAndCopyFile(pasteAsMarkdownSrcFile, tempTxtFileName);
ContentCopyAndPasteAsMarkdownCase3(tempTxtFileName);
var result = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempTxtFileName),
Path.Combine(testFilesFolderPath, pasteAsMarkdownResultFile),
compareFormatting: true);
Assert.IsTrue(result.IsConsistent, "Paste as markdown using shortcut failed.");
}
[TestMethod]
[TestCategory("AdvancedPasteUITest")]
[TestCategory("PasteAsJSONCase1")]
public void TestCasePasteAsJSONCase1()
{
if (_notepadSettingsChanged == false)
{
ChangeNotePadSettings();
}
// Copy some XML or CSV text(or any other text, it will be converted to simple JSON object)
// Paste the text using set hotkey and confirm that pasted text is converted to JSON
DeleteAndCopyFile(pasteAsJsonFileName, tempTxtFileName);
ContentCopyAndPasteAsJsonCase1(tempTxtFileName);
var result = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempTxtFileName),
Path.Combine(testFilesFolderPath, pasteAsJsonResultFile),
compareFormatting: true);
Assert.IsTrue(result.IsConsistent, "Paste as Json using shortcut failed.");
}
[TestMethod]
[TestCategory("AdvancedPasteUITest")]
[TestCategory("PasteAsJSONCase2")]
public void TestCasePasteAsJSONCase2()
{
if (_notepadSettingsChanged == false)
{
ChangeNotePadSettings();
}
// Copy some text(same as in the previous step or different.If nothing is coppied between steps, previously pasted JSON text will be picked up from clipboard and converted again to nested JSON).
// Open Advanced Paste window using hotkey, click Paste as markdown button and confirm that pasted text is converted to markdown
DeleteAndCopyFile(pasteAsJsonFileName, tempTxtFileName);
ContentCopyAndPasteAsJsonCase2(tempTxtFileName);
var result = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempTxtFileName),
Path.Combine(testFilesFolderPath, pasteAsJsonResultFile),
compareFormatting: true);
Assert.IsTrue(result.IsConsistent, "Paste as Json using shortcut failed.");
}
[TestMethod]
[TestCategory("AdvancedPasteUITest")]
[TestCategory("PasteAsJSONCase3")]
public void TestCasePasteAsJSONCase3()
{
if (_notepadSettingsChanged == false)
{
ChangeNotePadSettings();
}
// Copy some text(same as in the previous step or different.If nothing is coppied between steps, previously pasted JSON text will be picked up from clipboard and converted again to nested JSON).
// Open Advanced Paste window using hotkey, press Ctrl + 3 and confirm that pasted text is converted to markdown
DeleteAndCopyFile(pasteAsJsonFileName, tempTxtFileName);
ContentCopyAndPasteAsJsonCase3(tempTxtFileName);
var result = FileReader.CompareRtfFiles(
Path.Combine(testFilesFolderPath, tempTxtFileName),
Path.Combine(testFilesFolderPath, pasteAsJsonResultFile),
compareFormatting: true);
Assert.IsTrue(result.IsConsistent, "Paste as Json using shortcut failed.");
}
/*
* Clipboard History
- [] Open Settings and Enable clipboard history (if not enabled already). Open Advanced Paste window with hotkey, click Clipboard history and try deleting some entry. Check OS clipboard history (Win+V), and confirm that the same entry no longer exist.
- [] Open Advanced Paste window with hotkey, click Clipboard history, and click any entry (but first). Observe that entry is put on top of clipboard history. Check OS clipboard history (Win+V), and confirm that the same entry is on top of the clipboard.
- [] Open Settings and Disable clipboard history. Open Advanced Paste window with hotkey and observe that Clipboard history button is disabled.
* Disable Advanced Paste, try different Advanced Paste hotkeys and confirm that it's disabled and nothing happens.
*/
private void TestCaseClipboardHistory()
{
}
private void ContentCopyAndPasteDirectly(string fileName, bool isRTF = false)
{
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.V);
Thread.Sleep(1000);
this.SendKeys(Key.Backspace);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
process.Kill(true);
}
private void ContentCopyAndPasteWithShortcutThenPasteAgain(string fileName, bool isRTF = false)
{
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
this.SendKeys(Key.Win, Key.LCtrl, Key.Alt, Key.O);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.V);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
process.Kill(true);
}
private void ContentCopyAndPasteCase3(string fileName, bool isRTF = false)
{
// Copy some rich text again.
// Open Advanced Paste window using hotkey, click Paste as Plain Text button and confirm that plain text without any formatting is pasted.
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
// Open Advanced Paste window using hotkey
this.SendKeys(Key.Win, Key.Shift, Key.V);
Thread.Sleep(15000);
// Click Paste as Plain Text button and confirm that plain text without any formatting is pasted.
var apWind = this.Find<Window>("Advanced Paste", global: true);
apWind.Find<TextBlock>("Paste as plain text").Click();
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
process.Kill(true);
}
private void ContentCopyAndPasteCase4(string fileName, bool isRTF = false)
{
// Copy some rich text again.
// Open Advanced Paste window using hotkey, press Ctrl + 1 and confirm that plain text without any formatting is pasted.
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
// Open Advanced Paste window using hotkey
this.SendKeys(Key.Win, Key.Shift, Key.V);
Thread.Sleep(1000);
// press Ctrl + 1 and confirm that plain text without any formatting is pasted.
this.SendKeys(Key.LCtrl, Key.Num1);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
process.Kill(true);
}
private void ContentCopyAndPasteAsMarkdownCase1(string fileName, bool isRTF = false)
{
// Copy some rich text again.
// Open Advanced Paste window using hotkey, press Ctrl + 1 and confirm that plain text without any formatting is pasted.
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
this.SendKeys(Key.Win, Key.LCtrl, Key.Alt, Key.M);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
window.Close();
}
private void ContentCopyAndPasteAsMarkdownCase2(string fileName, bool isRTF = false)
{
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
// Open Advanced Paste window using hotkey
this.SendKeys(Key.Win, Key.Shift, Key.V);
Thread.Sleep(15000);
// click Paste as markdown button and confirm that pasted text is converted to markdown
var apWind = this.Find<Window>("Advanced Paste", global: true);
apWind.Find<TextBlock>("Paste as markdown").Click();
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
window.Close();
}
private void ContentCopyAndPasteAsMarkdownCase3(string fileName, bool isRTF = false)
{
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
// Open Advanced Paste window using hotkey
this.SendKeys(Key.Win, Key.Shift, Key.V);
Thread.Sleep(15000);
this.SendKeys(Key.LCtrl, Key.Num2);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
window.Close();
}
private void ContentCopyAndPasteAsJsonCase1(string fileName, bool isRTF = false)
{
// Copy some rich text again.
// Open Advanced Paste window using hotkey, press Ctrl + 1 and confirm that plain text without any formatting is pasted.
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
this.SendKeys(Key.Win, Key.LCtrl, Key.Alt, Key.J);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
window.Close();
}
private void ContentCopyAndPasteAsJsonCase2(string fileName, bool isRTF = false)
{
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
// Open Advanced Paste window using hotkey
this.SendKeys(Key.Win, Key.Shift, Key.V);
Thread.Sleep(15000);
// click Paste as markdown button and confirm that pasted text is converted to markdown
var apWind = this.Find<Window>("Advanced Paste", global: true);
apWind.Find<TextBlock>("Paste as JSON").Click();
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
window.Close();
}
private void ContentCopyAndPasteAsJsonCase3(string fileName, bool isRTF = false)
{
string tempFile = Path.Combine(testFilesFolderPath, fileName);
Process process = Process.Start(isRTF ? wordpadPath : "notepad.exe", tempFile);
if (process == null)
{
throw new InvalidOperationException($"Failed to start {(isRTF ? "WordPad" : "Notepad")}.");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle(Path.GetFileName(tempFile), isRTF);
window.Click();
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.A);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.C);
Thread.Sleep(1000);
this.SendKeys(Key.Delete);
Thread.Sleep(1000);
// Open Advanced Paste window using hotkey
this.SendKeys(Key.Win, Key.Shift, Key.V);
Thread.Sleep(15000);
this.SendKeys(Key.LCtrl, Key.Num3);
Thread.Sleep(1000);
this.SendKeys(Key.LCtrl, Key.S);
Thread.Sleep(1000);
window.Close();
}
private string DeleteAndCopyFile(string sourceFileName, string destinationFileName)
{
string sourcePath = Path.Combine(testFilesFolderPath, sourceFileName);
string destinationPath = Path.Combine(testFilesFolderPath, destinationFileName);
// Check if source file exists
if (!File.Exists(sourcePath))
{
throw new FileNotFoundException($"Source file not found: {sourcePath}");
}
// Delete destination file if it exists
if (File.Exists(destinationPath))
{
try
{
File.Delete(destinationPath);
}
catch (IOException ex)
{
throw new IOException($"Failed to delete file {destinationPath}. The file may be in use: {ex.Message}", ex);
}
}
// Copy the source file to the destination
try
{
File.Copy(sourcePath, destinationPath);
}
catch (IOException ex)
{
throw new IOException($"Failed to copy file from {sourcePath} to {destinationPath}: {ex.Message}", ex);
}
return destinationPath;
}
private void ChangeNotePadSettings()
{
Process process = Process.Start("notepad.exe");
if (process == null)
{
throw new InvalidOperationException($"Failed to start Notepad.exe");
}
Thread.Sleep(15000);
var window = FindWindowWithFlexibleTitle("Untitled", false);
window.Find<PowerToys.UITest.Button>("Settings").Click();
var combobox = window.Find<PowerToys.UITest.ComboBox>("Opening files");
combobox.SelectTxt("Open in a new window");
window.Find<Group>("When Notepad starts").Click();
window.Find<PowerToys.UITest.RadioButton>("Open a new window").Select();
_notepadSettingsChanged = true;
window.Close();
}
/// <summary>
/// Finds a window with flexible title matching, trying multiple title variations
/// </summary>
/// <param name="baseTitle">The base title to search for</param>
/// <param name="isRTF">Whether the window is a WordPad window</param>
/// <returns>The found Window element or throws an exception if not found</returns>
private Window FindWindowWithFlexibleTitle(string baseTitle, bool isRTF)
{
Window? window = null;
string appType = isRTF ? "WordPad" : "Notepad";
// Try different title variations
string[] titleVariations = new string[]
{
baseTitle + (isRTF ? " - WordPad" : " - Notepad"), // With suffix
baseTitle, // Without suffix
Path.GetFileNameWithoutExtension(baseTitle) + (isRTF ? " - WordPad" : " - Notepad"), // Without extension, with suffix
Path.GetFileNameWithoutExtension(baseTitle), // Without extension, without suffix
};
Exception? lastException = null;
foreach (string title in titleVariations)
{
try
{
window = this.Find<Window>(title, global: true);
if (window != null)
{
return window;
}
}
catch (Exception ex)
{
// Save the exception, but continue trying other variations
lastException = ex;
}
}
// If we couldn't find the window with any variation, throw an exception with details
throw new InvalidOperationException(
$"Failed to find {appType} window with title containing '{baseTitle}'. ");
}
private static void CopySettingsFileBeforeTests()
{
try
{
// Determine the assembly location and test files path
string? assemblyLocation = Path.GetDirectoryName(typeof(AdvancedPasteUITest).Assembly.Location);
if (assemblyLocation == null)
{
Debug.WriteLine("ERROR: Failed to get assembly location");
return;
}
string testFilesFolder = Path.Combine(assemblyLocation, "TestFiles");
if (!Directory.Exists(testFilesFolder))
{
Debug.WriteLine($"ERROR: Test files directory not found at: {testFilesFolder}");
return;
}
// Settings file source path
string settingsFileName = "settings.json";
string sourceSettingsPath = Path.Combine(testFilesFolder, settingsFileName);
// Make sure the source file exists
if (!File.Exists(sourceSettingsPath))
{
Debug.WriteLine($"ERROR: Settings file not found at: {sourceSettingsPath}");
return;
}
// Determine the target directory in %LOCALAPPDATA%
string targetDirectory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft",
"PowerToys",
"AdvancedPaste");
// Create the directory if it doesn't exist
if (!Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
string targetSettingsPath = Path.Combine(targetDirectory, settingsFileName);
// Copy the file and overwrite if it exists
File.Copy(sourceSettingsPath, targetSettingsPath, true);
Debug.WriteLine($"Successfully copied settings file from {sourceSettingsPath} to {targetSettingsPath}");
}
catch (Exception ex)
{
Debug.WriteLine($"ERROR copying settings file: {ex.Message}");
}
}
}
}

View File

@@ -1,85 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace Microsoft.AdvancedPaste.UITests.Helper;
public class FileReader
{
public static string ReadContent(string filePath)
{
try
{
return File.ReadAllText(filePath);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to read file: {ex.Message}", ex);
}
}
public static string ReadRTFPlainText(string filePath)
{
try
{
using (var rtb = new System.Windows.Forms.RichTextBox())
{
rtb.Rtf = File.ReadAllText(filePath);
return rtb.Text;
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to read plain text from file: {ex.Message}", ex);
}
}
/// <summary>
/// Compares the contents of two RTF files to check if they are consistent.
/// </summary>
/// <param name="firstFilePath">Path to the first RTF file</param>
/// <param name="secondFilePath">Path to the second RTF file</param>
/// <param name="compareFormatting">If true, compares the raw RTF content (including formatting).
/// If false, compares only the plain text content.</param>
/// <returns>
/// A tuple containing: (bool isConsistent, string firstContent, string secondContent)
/// - isConsistent: true if the files are consistent according to the comparison method
/// - firstContent: the content of the first file
/// - secondContent: the content of the second file
/// </returns>
public static (bool IsConsistent, string FirstContent, string SecondContent) CompareRtfFiles(
string firstFilePath,
string secondFilePath,
bool compareFormatting = false)
{
try
{
string firstContent, secondContent;
if (compareFormatting)
{
// Compare raw RTF content (including formatting)
firstContent = ReadContent(firstFilePath);
secondContent = ReadContent(secondFilePath);
}
else
{
// Compare only the plain text content
firstContent = ReadRTFPlainText(firstFilePath);
secondContent = ReadRTFPlainText(secondFilePath);
}
bool isConsistent = string.Equals(firstContent, secondContent, StringComparison.Ordinal);
return (isConsistent, firstContent, secondContent);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to compare RTF files: {ex.Message}", ex);
}
}
}

View File

@@ -1,6 +0,0 @@
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@@ -1,8 +0,0 @@
{
"note": {
"to": "Tove",
"from": "Jani",
"heading": "Reminder",
"body": "Don't forget me this weekend!"
}
}

View File

@@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<h2 title="I'm a header">The title Attribute</h2>
<p title="I'm a tooltip">Mouse over this paragraph, to display the title attribute as a tooltip.</p>
</body>
</html>

View File

@@ -1,3 +0,0 @@
## The title Attribute
Mouse over this paragraph, to display the title attribute as a tooltip.

View File

@@ -1 +0,0 @@
{"properties":{"IsAdvancedAIEnabled":{"value":false},"ShowCustomPreview":{"value":true},"CloseAfterLosingFocus":{"value":false},"advanced-paste-ui-hotkey":{"win":true,"ctrl":false,"alt":false,"shift":true,"code":86,"key":""},"paste-as-plain-hotkey":{"win":true,"ctrl":true,"alt":true,"shift":false,"code":79,"key":""},"paste-as-markdown-hotkey":{"win":true,"ctrl":true,"alt":true,"shift":false,"code":77,"key":""},"paste-as-json-hotkey":{"win":true,"ctrl":true,"alt":true,"shift":false,"code":74,"key":""},"custom-actions":{"value":[]},"additional-actions":{"image-to-text":{"shortcut":{"win":false,"ctrl":false,"alt":false,"shift":false,"code":0,"key":""},"isShown":true},"paste-as-file":{"isShown":true,"paste-as-txt-file":{"shortcut":{"win":false,"ctrl":false,"alt":false,"shift":false,"code":0,"key":""},"isShown":true},"paste-as-png-file":{"shortcut":{"win":false,"ctrl":false,"alt":false,"shift":false,"code":0,"key":""},"isShown":true},"paste-as-html-file":{"shortcut":{"win":false,"ctrl":false,"alt":false,"shift":false,"code":0,"key":""},"isShown":true}},"transcode":{"isShown":true,"transcode-to-mp3":{"shortcut":{"win":false,"ctrl":false,"alt":false,"shift":false,"code":0,"key":""},"isShown":true},"transcode-to-mp4":{"shortcut":{"win":false,"ctrl":false,"alt":false,"shift":false,"code":0,"key":""},"isShown":true}}}},"name":"AdvancedPaste","version":"1"}

View File

@@ -1,41 +0,0 @@
## [Advanced Paste](tests-checklist-template-advanced-paste-section.md)
NOTES:
When using Advanced Paste, make sure that window focused while starting/using Advanced paste is text editor or has text input field focused (e.g. Word).
* Paste As Plain Text
- [x] Copy some rich text (e.g word of the text is different color, another work is bold, underlined, etd.).
- [x] Paste the text using standard Windows Ctrl + V shortcut and ensure that rich text is pasted (with all colors, formatting, etc.)
- [x] Paste the text using Paste As Plain Text activation shortcut and ensure that plain text without any formatting is pasted.
- [x] Paste again the text using standard Windows Ctrl + V shortcut and ensure the text is now pasted plain without formatting as well.
- [x] Copy some rich text again.
- [x] Open Advanced Paste window using hotkey, click Paste as Plain Text button and confirm that plain text without any formatting is pasted.
- [x] Copy some rich text again.
- [x] Open Advanced Paste window using hotkey, press Ctrl + 1 and confirm that plain text without any formatting is pasted.
* Paste As Markdown
- [] Open Settings and set Paste as Markdown directly hotkey
- [x] Copy some text (e.g. some HTML text - convertible to Markdown)
- [x] Paste the text using set hotkey and confirm that pasted text is converted to markdown
- [x] Copy some text (same as in the previous step or different. If nothing is coppied between steps, previously pasted Markdown text will be picked up from clipboard and converted again to nested Markdown).
- [x] Open Advanced Paste window using hotkey, click Paste as markdown button and confirm that pasted text is converted to markdown
- [x] Copy some text (same as in the previous step or different. If nothing is coppied between steps, previously pasted Markdown text will be picked up from clipboard and converted again to nested Markdown).
- [x] Open Advanced Paste window using hotkey, press Ctrl + 2 and confirm that pasted text is converted to markdown
* Paste As JSON
- [] Open Settings and set Paste as JSON directly hotkey
- [x] Copy some XML or CSV text (or any other text, it will be converted to simple JSON object)
- [x] Paste the text using set hotkey and confirm that pasted text is converted to JSON
- [x] Copy some text (same as in the previous step or different. If nothing is coppied between steps, previously pasted JSON text will be picked up from clipboard and converted again to nested JSON).
- [x] Open Advanced Paste window using hotkey, click Paste as markdown button and confirm that pasted text is converted to markdown
- [x] Copy some text (same as in the previous step or different. If nothing is coppied between steps, previously pasted JSON text will be picked up from clipboard and converted again to nested JSON).
- [x] Open Advanced Paste window using hotkey, press Ctrl + 3 and confirm that pasted text is converted to markdown
* Paste as custom format using AI
- [] Open Settings, navigate to Enable Paste with AI and set OpenAI key.
- [] Copy some text to clipboard. Any text.
- [] Open Advanced Paste window using hotkey, and confirm that Custom intput text box is now enabled. Write "Insert smiley after every word" and press Enter. Observe that result preview shows coppied text with smileys between words. Press Enter to paste the result and observe that it is pasted.
- [] Open Advanced Paste window using hotkey. Input some query (any, feel free to play around) and press Enter. When result is shown, click regenerate button, to see if new result is generated. Select one of the results and paste. Observe that correct result is pasted.
- [] Create few custom actions. Set up hotkey for custom actions and confirm they work. Enable/disable custom actions and confirm that the change is reflected in Advanced Paste UI - custom action is not listed. Try different ctrl + <num> in-app shortcuts for custom actions. Try moving custom actions up/down and confirm that the change is reflected in Advanced Paste UI.
- [] Open Settings and disable Custom format preview. Open Advanced Paste window with hotkey, enter some query and press enter. Observe that result is now pasted right away, without showing the preview first.
- [] Open Settings and Disable Enable Paste with AI. Open Advanced Paste window with hotkey and observe that Custom Input text box is now disabled.
* Clipboard History
- [] Open Settings and Enable clipboard history (if not enabled already). Open Advanced Paste window with hotkey, click Clipboard history and try deleting some entry. Check OS clipboard history (Win+V), and confirm that the same entry no longer exist.
- [] Open Advanced Paste window with hotkey, click Clipboard history, and click any entry (but first). Observe that entry is put on top of clipboard history. Check OS clipboard history (Win+V), and confirm that the same entry is on top of the clipboard.
- [] Open Settings and Disable clipboard history. Open Advanced Paste window with hotkey and observe that Clipboard history button is disabled.
* Disable Advanced Paste, try different Advanced Paste hotkeys and confirm that it's disabled and nothing happens.

View File

@@ -4,8 +4,8 @@
{
"fuzzer": {
"$type": "libfuzzerDotNet",
"dll": "HostsEditor.FuzzTests.dll",
"class": "HostsEditor.FuzzTests.FuzzTests",
"dll": "Hosts.FuzzTests.dll",
"class": "Hosts.FuzzTests.FuzzTests",
"method": "FuzzValidIPv4",
"FuzzingTargetBinaries": [
"PowerToys.Hosts.dll"
@@ -35,8 +35,8 @@
// the DLL and PDB files
// you will need to add any other files required
// (globs are supported)
"HostsEditor.FuzzTests.dll",
"HostsEditor.FuzzTests.pdb",
"Hosts.FuzzTests.dll",
"Hosts.FuzzTests.pdb",
"Microsoft.Windows.SDK.NET.dll",
"WinRT.Runtime.dll"
],
@@ -45,8 +45,8 @@
{
"fuzzer": {
"$type": "libfuzzerDotNet",
"dll": "HostsEditor.FuzzTests.dll",
"class": "HostsEditor.FuzzTests.FuzzTests",
"dll": "Hosts.FuzzTests.dll",
"class": "Hosts.FuzzTests.FuzzTests",
"method": "FuzzValidIPv6",
"FuzzingTargetBinaries": [
"PowerToys.Hosts.dll"
@@ -76,8 +76,8 @@
// the DLL and PDB files
// you will need to add any other files required
// (globs are supported)
"HostsEditor.FuzzTests.dll",
"HostsEditor.FuzzTests.pdb",
"Hosts.FuzzTests.dll",
"Hosts.FuzzTests.pdb",
"Microsoft.Windows.SDK.NET.dll",
"WinRT.Runtime.dll"
],
@@ -86,8 +86,8 @@
{
"fuzzer": {
"$type": "libfuzzerDotNet",
"dll": "HostsEditor.FuzzTests.dll",
"class": "HostsEditor.FuzzTests.FuzzTests",
"dll": "Hosts.FuzzTests.dll",
"class": "Hosts.FuzzTests.FuzzTests",
"method": "FuzzValidHosts",
"FuzzingTargetBinaries": [
"PowerToys.Hosts.dll"
@@ -117,8 +117,8 @@
// the DLL and PDB files
// you will need to add any other files required
// (globs are supported)
"HostsEditor.FuzzTests.dll",
"HostsEditor.FuzzTests.pdb",
"Hosts.FuzzTests.dll",
"Hosts.FuzzTests.pdb",
"Microsoft.Windows.SDK.NET.dll",
"WinRT.Runtime.dll"
],
@@ -127,8 +127,8 @@
{
"fuzzer": {
"$type": "libfuzzerDotNet",
"dll": "HostsEditor.FuzzTests.dll",
"class": "HostsEditor.FuzzTests.FuzzTests",
"dll": "Hosts.FuzzTests.dll",
"class": "Hosts.FuzzTests.FuzzTests",
"method": "FuzzWriteAsync",
"FuzzingTargetBinaries": [
"PowerToys.Hosts.dll"
@@ -160,8 +160,8 @@
// (globs are supported)
"Castle.Core.dll",
"CommunityToolkit.Mvvm.dll",
"HostsEditor.FuzzTests.dll",
"HostsEditor.FuzzTests.pdb",
"Hosts.FuzzTests.dll",
"Hosts.FuzzTests.pdb",
"Microsoft.Windows.SDK.NET.dll",
"Moq.dll",
"System.IO.Abstractions.dll",

View File

@@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<PropertyGroup>
<RootNamespace>PowerOCR.UITests</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Library</OutputType>
<RunVSTest>false</RunVSTest>
</PropertyGroup>
<PropertyGroup>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\tests\PowerOCR.UITests\</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest" />
<ProjectReference Include="..\..\..\common\UITestAutomation\UITestAutomation.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,59 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.PowerToys.UITest;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static Microsoft.PowerToys.UITest.UITestBase;
namespace PowerOCR.UITests;
[TestClass]
public class PowerOCRTests : UITestBase
{
public PowerOCRTests()
: base(PowerToysModule.PowerToysSettings, WindowSize.Medium)
{
}
[TestInitialize]
public void TestInitialize()
{
if (FindAll<NavigationViewItem>("Text Extractor").Count == 0)
{
// Expand Advanced list-group if needed
Find<NavigationViewItem>("System Tools").Click();
}
Find<NavigationViewItem>("Text Extractor").Click();
Find<ToggleSwitch>("Enable Text Extractor").Toggle(true);
SendKeys(Key.Win, Key.D);
}
[TestMethod("PowerOCR.DetectTextExtractor")]
[TestCategory("PowerOCR Detection")]
public void DetectTextExtractorTest()
{
try
{
SendKeys(Key.Win, Key.Shift, Key.T);
Thread.Sleep(5000);
var textExtractorWindow = Find("TextExtractor", 10000, true);
Assert.IsNotNull(textExtractorWindow, "TextExtractor window should be found after hotkey activation");
Console.WriteLine("✓ TextExtractor window detected successfully after hotkey activation");
SendKeys(Key.Esc);
}
catch (Exception ex)
{
Console.WriteLine($"Failed to detect TextExtractor window: {ex.Message}");
Assert.Fail("TextExtractor window was not found after hotkey activation");
}
}
}

View File

@@ -5,7 +5,7 @@
<ProjectGuid>{A85D4D9F-9A39-4B5D-8B5A-9F2D5C9A8B4C}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>WorkspacesLibUnitTests</RootNamespace>
<ProjectName>Workspaces.Lib.UnitTests</ProjectName>
<ProjectName>WorkspacesLibUnitTests</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">

View File

@@ -1,46 +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.Threading;
namespace Microsoft.CmdPal.Common.Helpers;
/// <summary>
/// Thread-safe boolean implementation using atomic operations
/// </summary>
public struct InterlockedBoolean(bool initialValue = false)
{
private int _value = initialValue ? 1 : 0;
/// <summary>
/// Gets or sets the boolean value atomically
/// </summary>
public bool Value
{
get => Volatile.Read(ref _value) == 1;
set => Interlocked.Exchange(ref _value, value ? 1 : 0);
}
/// <summary>
/// Atomically sets the value to true
/// </summary>
/// <returns>True if the value was previously false, false if it was already true</returns>
public bool Set()
{
return Interlocked.Exchange(ref _value, 1) == 0;
}
/// <summary>
/// Atomically sets the value to false
/// </summary>
/// <returns>True if the value was previously true, false if it was already false</returns>
public bool Clear()
{
return Interlocked.Exchange(ref _value, 0) == 1;
}
public override int GetHashCode() => Value.GetHashCode();
public override string ToString() => Value.ToString();
}

View File

@@ -1,139 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CmdPal.Common.Helpers;
/// <summary>
/// An async gate that ensures only one operation runs at a time.
/// If ExecuteAsync is called while already executing, it cancels the current execution
/// and starts the operation again (superseding behavior).
/// </summary>
public class SupersedingAsyncGate : IDisposable
{
private readonly Func<CancellationToken, Task> _action;
private readonly Lock _lock = new();
private int _callId;
private TaskCompletionSource<bool>? _currentTcs;
private CancellationTokenSource? _currentCancellationSource;
private Task? _executingTask;
public SupersedingAsyncGate(Func<CancellationToken, Task> action)
{
ArgumentNullException.ThrowIfNull(action);
_action = action;
}
/// <summary>
/// Executes the configured action. If another execution is running, this call will
/// cancel the current execution and restart the operation.
/// </summary>
/// <param name="cancellationToken">Optional external cancellation token</param>
public async Task ExecuteAsync(CancellationToken cancellationToken = default)
{
TaskCompletionSource<bool> tcs;
lock (_lock)
{
_currentCancellationSource?.Cancel();
_currentTcs?.TrySetException(new OperationCanceledException("Superseded by newer call"));
tcs = new();
_currentTcs = tcs;
_callId++;
var shouldStartExecution = _executingTask is null;
if (shouldStartExecution)
{
_executingTask = Task.Run(ExecuteLoop, CancellationToken.None);
}
}
await using var ctr = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
await tcs.Task;
}
private async Task ExecuteLoop()
{
try
{
while (true)
{
TaskCompletionSource<bool>? currentTcs;
CancellationTokenSource? currentCts;
int currentCallId;
lock (_lock)
{
currentTcs = _currentTcs;
currentCallId = _callId;
if (currentTcs is null)
{
break;
}
_currentCancellationSource?.Dispose();
_currentCancellationSource = new();
currentCts = _currentCancellationSource;
}
try
{
await _action(currentCts.Token);
CompleteIfCurrent(currentTcs, currentCallId, static t => t.TrySetResult(true));
}
catch (OperationCanceledException)
{
CompleteIfCurrent(currentTcs, currentCallId, tcs => tcs.SetCanceled(currentCts.Token));
}
catch (Exception ex)
{
CompleteIfCurrent(currentTcs, currentCallId, tcs => tcs.TrySetException(ex));
}
}
}
finally
{
lock (_lock)
{
_currentTcs = null;
_currentCancellationSource?.Dispose();
_currentCancellationSource = null;
_executingTask = null;
}
}
}
private void CompleteIfCurrent(
TaskCompletionSource<bool> candidate,
int id,
Action<TaskCompletionSource<bool>> complete)
{
lock (_lock)
{
if (_currentTcs == candidate && _callId == id)
{
complete(candidate);
_currentTcs = null;
}
}
}
public void Dispose()
{
lock (_lock)
{
_currentCancellationSource?.Cancel();
_currentCancellationSource?.Dispose();
_currentTcs?.TrySetException(new ObjectDisposedException(nameof(SupersedingAsyncGate)));
_currentTcs = null;
}
GC.SuppressFinalize(this);
}
}

View File

@@ -28,24 +28,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\common\ManagedCsWin32\ManagedCsWin32.csproj" />
<ProjectReference Include="..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -9,7 +9,3 @@ GetWindowRect
GetMonitorInfo
SetWindowPos
MonitorFromWindow
SHOW_WINDOW_CMD
ShellExecuteEx
SEE_MASK_INVOKEIDLIST

View File

@@ -1,99 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.CmdPal.Common.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CmdPal.Common.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Open path in console.
/// </summary>
internal static string Indexer_Command_OpenPathInConsole {
get {
return ResourceManager.GetString("Indexer_Command_OpenPathInConsole", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Properties.
/// </summary>
internal static string Indexer_Command_OpenProperties {
get {
return ResourceManager.GetString("Indexer_Command_OpenProperties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open with.
/// </summary>
internal static string Indexer_Command_OpenWith {
get {
return ResourceManager.GetString("Indexer_Command_OpenWith", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Show in folder.
/// </summary>
internal static string Indexer_Command_ShowInFolder {
get {
return ResourceManager.GetString("Indexer_Command_ShowInFolder", resourceCulture);
}
}
}
}

View File

@@ -1,132 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Indexer_Command_OpenPathInConsole" xml:space="preserve">
<value>Open path in console</value>
</data>
<data name="Indexer_Command_OpenProperties" xml:space="preserve">
<value>Properties</value>
</data>
<data name="Indexer_Command_OpenWith" xml:space="preserve">
<value>Open with</value>
</data>
<data name="Indexer_Command_ShowInFolder" xml:space="preserve">
<value>Show in folder</value>
</data>
</root>

View File

@@ -19,13 +19,13 @@ public interface IExtensionService
Task SignalStopExtensionsAsync();
event TypedEventHandler<IExtensionService, IEnumerable<IExtensionWrapper>>? OnExtensionAdded;
public event TypedEventHandler<IExtensionService, IEnumerable<IExtensionWrapper>>? OnExtensionAdded;
event TypedEventHandler<IExtensionService, IEnumerable<IExtensionWrapper>>? OnExtensionRemoved;
public event TypedEventHandler<IExtensionService, IEnumerable<IExtensionWrapper>>? OnExtensionRemoved;
void EnableExtension(string extensionUniqueId);
public void EnableExtension(string extensionUniqueId);
void DisableExtension(string extensionUniqueId);
public void DisableExtension(string extensionUniqueId);
///// <summary>
///// Gets a boolean indicating whether the extension was disabled due to the corresponding Windows optional feature

View File

@@ -1,27 +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 Microsoft.CmdPal.Common.Services;
public interface IRunHistoryService
{
/// <summary>
/// Gets the run history.
/// </summary>
/// <returns>A list of run history items.</returns>
IReadOnlyList<string> GetRunHistory();
/// <summary>
/// Clears the run history.
/// </summary>
void ClearRunHistory();
/// <summary>
/// Adds a run history item.
/// </summary>
/// <param name="item">The run history item to add.</param>
void AddRunHistoryItem(string item);
}

View File

@@ -1,168 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.ObjectModel;
using System.Diagnostics;
using ManagedCommon;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class AppExtensionHost : IExtensionHost
{
private static readonly GlobalLogPageContext _globalLogPageContext = new();
private static ulong _hostingHwnd;
public static ObservableCollection<LogMessageViewModel> LogMessages { get; } = [];
public ulong HostingHwnd => _hostingHwnd;
public string LanguageOverride => string.Empty;
public ObservableCollection<StatusMessageViewModel> StatusMessages { get; } = [];
public static void SetHostHwnd(ulong hostHwnd) => _hostingHwnd = hostHwnd;
public void DebugLog(string message)
{
#if DEBUG
this.ProcessLogMessage(new LogMessage(message));
#endif
}
public IAsyncAction HideStatus(IStatusMessage? message)
{
if (message == null)
{
return Task.CompletedTask.AsAsyncAction();
}
_ = Task.Run(() =>
{
ProcessHideStatusMessage(message);
});
return Task.CompletedTask.AsAsyncAction();
}
public void Log(string message)
{
this.ProcessLogMessage(new LogMessage(message));
}
public IAsyncAction LogMessage(ILogMessage? message)
{
if (message == null)
{
return Task.CompletedTask.AsAsyncAction();
}
Logger.LogDebug(message.Message);
_ = Task.Run(() =>
{
ProcessLogMessage(message);
});
// We can't just make a LogMessageViewModel : ExtensionObjectViewModel
// because we don't necessarily know the page context. Butts.
return Task.CompletedTask.AsAsyncAction();
}
public void ProcessHideStatusMessage(IStatusMessage message)
{
Task.Factory.StartNew(
() =>
{
try
{
var vm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
if (vm != null)
{
StatusMessages.Remove(vm);
}
}
catch
{
}
},
CancellationToken.None,
TaskCreationOptions.None,
_globalLogPageContext.Scheduler);
}
public void ProcessLogMessage(ILogMessage message)
{
var vm = new LogMessageViewModel(message, _globalLogPageContext);
vm.SafeInitializePropertiesSynchronous();
Task.Factory.StartNew(
() =>
{
LogMessages.Add(vm);
},
CancellationToken.None,
TaskCreationOptions.None,
_globalLogPageContext.Scheduler);
}
public void ProcessStatusMessage(IStatusMessage message, StatusContext context)
{
// If this message is already in the list of messages, just bring it to the top
var oldVm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
if (oldVm != null)
{
Task.Factory.StartNew(
() =>
{
StatusMessages.Remove(oldVm);
StatusMessages.Add(oldVm);
},
CancellationToken.None,
TaskCreationOptions.None,
_globalLogPageContext.Scheduler);
return;
}
var vm = new StatusMessageViewModel(message, new(_globalLogPageContext));
vm.SafeInitializePropertiesSynchronous();
Task.Factory.StartNew(
() =>
{
StatusMessages.Add(vm);
},
CancellationToken.None,
TaskCreationOptions.None,
_globalLogPageContext.Scheduler);
}
public IAsyncAction ShowStatus(IStatusMessage? message, StatusContext context)
{
if (message == null)
{
return Task.CompletedTask.AsAsyncAction();
}
Debug.WriteLine(message.Message);
_ = Task.Run(() =>
{
ProcessStatusMessage(message, context);
});
return Task.CompletedTask.AsAsyncAction();
}
public abstract string? GetExtensionDisplayName();
}
public interface IAppHostService
{
AppExtensionHost GetDefaultHost();
AppExtensionHost GetHostForCommand(object? context, AppExtensionHost? currentHost);
}

View File

@@ -1,37 +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 Microsoft.CmdPal.Core.ViewModels;
public interface IRootPageService
{
/// <summary>
/// Gets the root page of the command palette. Return any IPage implementation that
/// represents the root view of this instance of the command palette.
/// </summary>
Microsoft.CommandPalette.Extensions.IPage GetRootPage();
/// <summary>
/// Pre-loads any necessary data or state before the root page is loaded.
/// This will be awaited before the root page and the user can do anything,
/// so ideally it should be quick and not block the UI thread for long.
/// </summary>
Task PreLoadAsync();
/// <summary>
/// Do any loading work that can be done after the root page is loaded and
/// displayed to the user.
/// This is run asynchronously, on a background thread.
/// </summary>
Task PostLoadRootPageAsync();
/// <summary>
/// Called when a command is performed. The context is the
/// sender context for the invoked command. This is typically the IListItem
/// or ICommandContextItem that was used to invoke the command.
/// </summary>
void OnPerformCommand(object? context, bool topLevel, AppExtensionHost? currentHost);
void GoHome();
}

View File

@@ -1,9 +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 Microsoft.CmdPal.Core.ViewModels.Messages;
public record OpenSettingsMessage()
{
}

View File

@@ -1,48 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>
<!-- For MVVM Toolkit Partial Properties/AOT support -->
<LangVersion>preview</LangVersion>
<!-- Disable SA1313 for Primary Constructor fields conflict https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors -->
<NoWarn>SA1313;</NoWarn>
</PropertyGroup>
<PropertyGroup>
<CsWinRTAotOptimizerEnabled>true</CsWinRTAotOptimizerEnabled>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Common" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="Microsoft.Windows.CsWin32">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="WyHash" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.CmdPal.Common\Microsoft.CmdPal.Common.csproj" />
<ProjectReference Include="..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
</ItemGroup>
</Project>

View File

@@ -1,4 +0,0 @@
{
"$schema": "https://aka.ms/CsWin32.schema.json",
"allowMarshaling": false
}

View File

@@ -1,19 +0,0 @@
GetPhysicallyInstalledSystemMemory
GlobalMemoryStatusEx
GetSystemInfo
CoCreateInstance
SetForegroundWindow
IsIconic
RegisterHotKey
SetWindowLongPtr
CallWindowProc
ShowWindow
SetForegroundWindow
SetFocus
SetActiveWindow
MonitorFromWindow
GetMonitorInfo
SHCreateStreamOnFileEx
CoAllowSetForegroundWindow
SHCreateStreamOnFileEx
SHLoadIndirectString

View File

@@ -4,7 +4,7 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Messages;
namespace Microsoft.CmdPal.UI.ViewModels;
@@ -38,8 +38,7 @@ public partial class AliasManager : ObservableObject
if (topLevelCommand != null)
{
WeakReferenceMessenger.Default.Send<ClearSearchMessage>();
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(topLevelCommand.GetPerformCommandMessage());
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(topLevelCommand));
return true;
}
}

View File

@@ -21,12 +21,8 @@ public partial class AppStateModel : ObservableObject
///////////////////////////////////////////////////////////////////////////
// STATE HERE
// Make sure that you make the setters public (JsonSerializer.Deserialize will fail silently otherwise)!
// Make sure that any new types you add are added to JsonSerializationContext!
public RecentCommandsManager RecentCommands { get; set; } = new();
public List<string> RunHistory { get; set; } = [];
// END SETTINGS
///////////////////////////////////////////////////////////////////////////
@@ -90,7 +86,7 @@ public partial class AppStateModel : ObservableObject
{
foreach (var item in newSettings)
{
savedSettings[item.Key] = item.Value?.DeepClone();
savedSettings[item.Key] = item.Value != null ? item.Value.DeepClone() : null;
}
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.AppStateModel.Options);
@@ -125,4 +121,20 @@ public partial class AppStateModel : ObservableObject
// now, the settings is just next to the exe
return Path.Combine(directory, "state.json");
}
// [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
// private static readonly JsonSerializerOptions _serializerOptions = new()
// {
// WriteIndented = true,
// Converters = { new JsonStringEnumConverter() },
// };
// private static readonly JsonSerializerOptions _deserializerOptions = new()
// {
// PropertyNameCaseInsensitive = true,
// IncludeFields = true,
// AllowTrailingCommas = true,
// PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate,
// ReadCommentHandling = JsonCommentHandling.Skip,
// };
}

View File

@@ -1,15 +1,15 @@
// Copyright (c) Microsoft Corporation
// 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.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.System;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandBarViewModel : ObservableObject,
IRecipient<UpdateCommandBarMessage>
@@ -149,7 +149,6 @@ public partial class CommandBarViewModel : ObservableObject,
if (command.HasMoreCommands)
{
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(command.Command.Model, command.Model));
return ContextKeybindingResult.KeepOpen;
}
else

View File

@@ -1,11 +1,13 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context) : CommandItemViewModel(new(contextItem), context), IContextItemViewModel
{

View File

@@ -1,13 +1,13 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBarContext
{
@@ -313,10 +313,6 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
Command = new(model.Command, PageContext);
Command.InitializeProperties();
// Extensions based on Command Palette SDK < 0.3 CommandItem class won't notify when Title changes because Command
// or Command.Name change. This is a workaround to ensure that the Title is always up-to-date for extensions with old SDK.
_itemTitle = model.Title;
UpdateProperty(nameof(Name));
UpdateProperty(nameof(Title));
UpdateProperty(nameof(Icon));
@@ -342,7 +338,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
var newContextMenu = more
.Select(item =>
{
if (item is ICommandContextItem contextItem)
if (item is CommandContextItem contextItem)
{
return new CommandContextItemViewModel(contextItem, PageContext) as IContextItemViewModel;
}
@@ -389,14 +385,6 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
switch (propertyName)
{
case nameof(Command.Name):
// Extensions based on Command Palette SDK < 0.3 CommandItem class won't notify when Title changes because Command
// or Command.Name change. This is a workaround to ensure that the Title is always up-to-date for extensions with old SDK.
var model = _commandItemModel.Unsafe;
if (model != null)
{
_itemTitle = model.Title;
}
UpdateProperty(nameof(Title));
UpdateProperty(nameof(Name));
break;

View File

@@ -1,28 +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.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandPaletteContentPageViewModel : ContentPageViewModel
{
public CommandPaletteContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
: base(model, scheduler, host)
{
}
public override ContentViewModel? ViewModelFromContent(IContent content, WeakReference<IPageContext> context)
{
ContentViewModel? viewModel = content switch
{
IFormContent form => new ContentFormViewModel(form, context),
IMarkdownContent markdown => new ContentMarkdownViewModel(markdown, context),
ITreeContent tree => new ContentTreeViewModel(tree, context),
_ => null,
};
return viewModel;
}
}

View File

@@ -1,19 +1,35 @@
// Copyright (c) Microsoft Corporation
// 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.ObjectModel;
using System.Diagnostics;
using ManagedCommon;
using Microsoft.CmdPal.Common.Services;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation;
namespace Microsoft.CmdPal.UI.ViewModels;
public sealed partial class CommandPaletteHost : AppExtensionHost, IExtensionHost
public sealed partial class CommandPaletteHost : IExtensionHost
{
// Static singleton, so that we can access this from anywhere
// Post MVVM - this should probably be like, a dependency injection thing.
public static CommandPaletteHost Instance { get; } = new();
private static readonly GlobalLogPageContext _globalLogPageContext = new();
private static ulong _hostingHwnd;
public ulong HostingHwnd => _hostingHwnd;
public string LanguageOverride => string.Empty;
public static ObservableCollection<LogMessageViewModel> LogMessages { get; } = [];
public ObservableCollection<StatusMessageViewModel> StatusMessages { get; } = [];
public IExtensionWrapper? Extension { get; }
private readonly ICommandProvider? _builtInProvider;
@@ -32,8 +48,145 @@ public sealed partial class CommandPaletteHost : AppExtensionHost, IExtensionHos
_builtInProvider = builtInProvider;
}
public override string? GetExtensionDisplayName()
public IAsyncAction ShowStatus(IStatusMessage? message, StatusContext context)
{
return Extension?.ExtensionDisplayName;
if (message == null)
{
return Task.CompletedTask.AsAsyncAction();
}
Debug.WriteLine(message.Message);
_ = Task.Run(() =>
{
ProcessStatusMessage(message, context);
});
return Task.CompletedTask.AsAsyncAction();
}
public IAsyncAction HideStatus(IStatusMessage? message)
{
if (message == null)
{
return Task.CompletedTask.AsAsyncAction();
}
_ = Task.Run(() =>
{
ProcessHideStatusMessage(message);
});
return Task.CompletedTask.AsAsyncAction();
}
public IAsyncAction LogMessage(ILogMessage? message)
{
if (message == null)
{
return Task.CompletedTask.AsAsyncAction();
}
Logger.LogDebug(message.Message);
_ = Task.Run(() =>
{
ProcessLogMessage(message);
});
// We can't just make a LogMessageViewModel : ExtensionObjectViewModel
// because we don't necessarily know the page context. Butts.
return Task.CompletedTask.AsAsyncAction();
}
public void ProcessLogMessage(ILogMessage message)
{
var vm = new LogMessageViewModel(message, _globalLogPageContext);
vm.SafeInitializePropertiesSynchronous();
if (Extension != null)
{
vm.ExtensionPfn = Extension.PackageFamilyName;
}
Task.Factory.StartNew(
() =>
{
LogMessages.Add(vm);
},
CancellationToken.None,
TaskCreationOptions.None,
_globalLogPageContext.Scheduler);
}
public void ProcessStatusMessage(IStatusMessage message, StatusContext context)
{
// If this message is already in the list of messages, just bring it to the top
var oldVm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
if (oldVm != null)
{
Task.Factory.StartNew(
() =>
{
StatusMessages.Remove(oldVm);
StatusMessages.Add(oldVm);
},
CancellationToken.None,
TaskCreationOptions.None,
_globalLogPageContext.Scheduler);
return;
}
var vm = new StatusMessageViewModel(message, new(_globalLogPageContext));
vm.SafeInitializePropertiesSynchronous();
if (Extension != null)
{
vm.ExtensionPfn = Extension.PackageFamilyName;
}
Task.Factory.StartNew(
() =>
{
StatusMessages.Add(vm);
},
CancellationToken.None,
TaskCreationOptions.None,
_globalLogPageContext.Scheduler);
}
public void ProcessHideStatusMessage(IStatusMessage message)
{
Task.Factory.StartNew(
() =>
{
try
{
var vm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
if (vm != null)
{
StatusMessages.Remove(vm);
}
}
catch
{
}
},
CancellationToken.None,
TaskCreationOptions.None,
_globalLogPageContext.Scheduler);
}
public static void SetHostHwnd(ulong hostHwnd) => _hostingHwnd = hostHwnd;
public void DebugLog(string message)
{
#if DEBUG
this.ProcessLogMessage(new LogMessage(message));
#endif
}
public void Log(string message)
{
this.ProcessLogMessage(new LogMessage(message));
}
}

View File

@@ -1,29 +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.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.UI.ViewModels;
public class CommandPalettePageViewModelFactory
: IPageViewModelFactoryService
{
private readonly TaskScheduler _scheduler;
public CommandPalettePageViewModelFactory(TaskScheduler scheduler)
{
_scheduler = scheduler;
}
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host)
{
return page switch
{
IListPage listPage => new ListViewModel(listPage, _scheduler, host) { IsNested = nested },
IContentPage contentPage => new CommandPaletteContentPageViewModel(contentPage, _scheduler, host),
_ => null,
};
}
}

View File

@@ -4,8 +4,7 @@
using ManagedCommon;
using Microsoft.CmdPal.Common.Services;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.DependencyInjection;

View File

@@ -3,8 +3,7 @@
// See the LICENSE file in the project root for more information.
using ManagedCommon;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.UI.ViewModels;
@@ -29,9 +28,9 @@ public partial class CommandSettingsViewModel(ICommandSettings? _unsafeSettings,
return;
}
if (model.SettingsPage != null)
if (model.SettingsPage is IContentPage page)
{
SettingsPage = new CommandPaletteContentPageViewModel(model.SettingsPage, mainThread, provider.ExtensionHost);
SettingsPage = new(page, mainThread, provider.ExtensionHost);
SettingsPage.InitializeProperties();
}
}

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandViewModel : ExtensionObjectViewModel
{

View File

@@ -2,7 +2,7 @@
// 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.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;

View File

@@ -2,7 +2,15 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.IO.Compression;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.CmdPal.Common;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation;
namespace Microsoft.CmdPal.UI.ViewModels.BuiltinCommands;

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Specialized;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
@@ -11,7 +10,7 @@ namespace Microsoft.CmdPal.UI.ViewModels.Commands;
public partial class LogMessagesPage : ListPage
{
private readonly List<IListItem> _listItems = [];
private readonly List<IListItem> _listItems = new();
public LogMessagesPage()
{
@@ -32,6 +31,7 @@ public partial class LogMessagesPage : ListPage
var li = new ListItem(new NoOpCommand())
{
Title = logMessageViewModel.Message,
Subtitle = logMessageViewModel.ExtensionPfn,
};
_listItems.Insert(0, li);
}

View File

@@ -6,8 +6,8 @@ using System.Collections.Immutable;
using System.Collections.Specialized;
using CommunityToolkit.Mvvm.Messaging;
using ManagedCommon;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Ext.Apps;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.DependencyInjection;
@@ -164,11 +164,6 @@ public partial class MainListPage : DynamicListPage,
if (_includeApps)
{
IEnumerable<IListItem> apps = AllAppsCommandProvider.Page.GetItems();
var appIds = apps.Select(app => app.Command.Id).ToArray();
// Remove any top level pinned apps and use the apps from AllAppsCommandProvider.Page.GetItems()
// since they contain details.
_filteredItems = _filteredItems.Where(item => item.Command is not AppCommand);
_filteredItems = _filteredItems.Concat(apps);
}
}
@@ -268,7 +263,7 @@ public partial class MainListPage : DynamicListPage,
{
nameMatch,
descriptionMatch,
isFallback ? 1 : 0, // Always give fallbacks a chance
isFallback ? 1 : 0, // Always give fallbacks a chance...
};
var max = scores.Max();
@@ -278,7 +273,8 @@ public partial class MainListPage : DynamicListPage,
// above "git" from "whatever"
max = max + extensionTitleMatch;
var matchSomething = max
// ... but downweight them
var matchSomething = (max / (isFallback ? 3 : 1))
+ (isAliasMatch ? 9001 : (isAliasSubstringMatch ? 1 : 0));
// If we matched title, subtitle, or alias (something real), then

View File

@@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO.Compression;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation;

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class ConfirmResultViewModel(IConfirmationArgs _args, WeakReference<IPageContext> context) :
ExtensionObjectViewModel(context)

View File

@@ -7,9 +7,8 @@ using AdaptiveCards.ObjectModel.WinUI3;
using AdaptiveCards.Templating;
using CommunityToolkit.Mvvm.Messaging;
using ManagedCommon;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Windows.Data.Json;

View File

@@ -2,8 +2,7 @@
// 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.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.UI.ViewModels;

View File

@@ -7,14 +7,14 @@ using System.Diagnostics.CodeAnalysis;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarContext
public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
{
private readonly ExtensionObject<IContentPage> _model;
@@ -47,7 +47,7 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
// Remember - "observable" properties from the model (via PropChanged)
// cannot be marked [ObservableProperty]
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, CommandPaletteHost host)
: base(model, scheduler, host)
{
_model = new(model);
@@ -91,12 +91,16 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
});
}
public virtual ContentViewModel? ViewModelFromContent(IContent content, WeakReference<IPageContext> context)
public static ContentViewModel? ViewModelFromContent(IContent content, WeakReference<IPageContext> context)
{
// The core ContentPageViewModel doesn't actually handle any content,
// so we just return null here.
// The real content is handled by the derived class CommandPaletteContentPageViewModel
return null;
ContentViewModel? viewModel = content switch
{
IFormContent form => new ContentFormViewModel(form, context),
IMarkdownContent markdown => new ContentMarkdownViewModel(markdown, context),
ITreeContent tree => new ContentTreeViewModel(tree, context),
_ => null,
};
return viewModel;
}
public override void InitializeProperties()
@@ -111,15 +115,15 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
Commands = model.Commands
.ToList()
.Select<IContextItem, IContextItemViewModel>(item =>
.Select(item =>
{
if (item is ICommandContextItem contextItem)
if (item is CommandContextItem contextItem)
{
return new CommandContextItemViewModel(contextItem, PageContext);
return new CommandContextItemViewModel(contextItem, PageContext) as IContextItemViewModel;
}
else
{
return new SeparatorContextItemViewModel();
return new SeparatorContextItemViewModel() as IContextItemViewModel;
}
})
.ToList();
@@ -172,13 +176,13 @@ public abstract partial class ContentPageViewModel : PageViewModel, ICommandBarC
.ToList()
.Select(item =>
{
if (item is ICommandContextItem contextItem)
if (item is CommandContextItem contextItem)
{
return new CommandContextItemViewModel(contextItem, PageContext) as IContextItemViewModel;
}
else
{
return new SeparatorContextItemViewModel();
return new SeparatorContextItemViewModel() as IContextItemViewModel;
}
})
.ToList();

View File

@@ -3,8 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.ObjectModel;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
@@ -38,7 +37,7 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
var root = model.RootContent;
if (root != null)
{
RootContent = ViewModelFromContent(root, PageContext);
RootContent = ContentPageViewModel.ViewModelFromContent(root, PageContext);
RootContent?.InitializeProperties();
UpdateProperty(nameof(RootContent));
UpdateProperty(nameof(Root));
@@ -49,20 +48,6 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
model.ItemsChanged += Model_ItemsChanged;
}
// Theoretically, we should unify this with the one in CommandPalettePageViewModelFactory
// and maybe just have a ContentViewModelFactory or something
public ContentViewModel? ViewModelFromContent(IContent content, WeakReference<IPageContext> context)
{
ContentViewModel? viewModel = content switch
{
IFormContent form => new ContentFormViewModel(form, context),
IMarkdownContent markdown => new ContentMarkdownViewModel(markdown, context),
ITreeContent tree => new ContentTreeViewModel(tree, context),
_ => null,
};
return viewModel;
}
// TODO: Does this need to hop to a _different_ thread, so that we don't block the extension while we're fetching?
private void Model_ItemsChanged(object sender, IItemsChangedEventArgs args) => FetchContent();
@@ -93,7 +78,7 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
var root = model.RootContent;
if (root != null)
{
RootContent = ViewModelFromContent(root, PageContext);
RootContent = ContentPageViewModel.ViewModelFromContent(root, PageContext);
}
else
{
@@ -118,7 +103,7 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
foreach (var item in newItems)
{
var viewModel = ViewModelFromContent(item, PageContext);
var viewModel = ContentPageViewModel.ViewModelFromContent(item, PageContext);
if (viewModel != null)
{
viewModel.InitializeProperties();

View File

@@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation
// 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 Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public abstract partial class ContentViewModel(WeakReference<IPageContext> context) :
ExtensionObjectViewModel(context)

View File

@@ -5,24 +5,32 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Diagnostics.Utilities;
using Windows.System;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class ContextMenuViewModel : ObservableObject,
IRecipient<UpdateCommandBarMessage>
IRecipient<UpdateCommandBarMessage>,
IRecipient<OpenContextMenuMessage>
{
public ICommandBarContext? SelectedItem
{
get => field;
set
{
if (field != null)
{
field.PropertyChanged -= SelectedItemPropertyChanged;
}
field = value;
UpdateContextItems();
SetSelectedItem(value);
OnPropertyChanged(nameof(SelectedItem));
}
}
@@ -42,6 +50,7 @@ public partial class ContextMenuViewModel : ObservableObject,
public ContextMenuViewModel()
{
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
WeakReferenceMessenger.Default.Register<OpenContextMenuMessage>(this);
}
public void Receive(UpdateCommandBarMessage message)
@@ -49,6 +58,43 @@ public partial class ContextMenuViewModel : ObservableObject,
SelectedItem = message.ViewModel;
}
public void Receive(OpenContextMenuMessage message)
{
FilterOnTop = message.ContextMenuFilterLocation == ContextMenuFilterLocation.Top;
ResetContextMenu();
OnPropertyChanging(nameof(FilterOnTop));
OnPropertyChanged(nameof(FilterOnTop));
}
private void SetSelectedItem(ICommandBarContext? value)
{
if (value != null)
{
value.PropertyChanged += SelectedItemPropertyChanged;
}
else
{
if (SelectedItem != null)
{
SelectedItem.PropertyChanged -= SelectedItemPropertyChanged;
}
}
UpdateContextItems();
}
private void SelectedItemPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(SelectedItem.HasMoreCommands):
UpdateContextItems();
break;
}
}
public void UpdateContextItems()
{
if (SelectedItem != null)
@@ -180,7 +226,7 @@ public partial class ContextMenuViewModel : ObservableObject,
ListHelpers.InPlaceUpdateList(FilteredItems, [.. CurrentContextMenu!]);
}
public void ResetContextMenu()
private void ResetContextMenu()
{
while (ContextMenuStack.Count > 1)
{

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class DetailsCommandsViewModel(
IDetailsElement _detailsElement,

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public abstract partial class DetailsDataViewModel(IPageContext context) : ExtensionObjectViewModel(context)
{

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public abstract partial class DetailsElementViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context) : ExtensionObjectViewModel(context)
{

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class DetailsLinkViewModel(
IDetailsElement _detailsElement,

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class DetailsSeparatorViewModel(
IDetailsElement _detailsElement,

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class DetailsTagsViewModel(
IDetailsElement _detailsElement,

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class DetailsViewModel(IDetails _details, WeakReference<IPageContext> context) : ExtensionObjectViewModel(context)
{

View File

@@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation
// 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 CommunityToolkit.Mvvm.ComponentModel;
using ManagedCommon;
namespace Microsoft.CmdPal.Core.ViewModels;
namespace Microsoft.CmdPal.UI.ViewModels;
public abstract partial class ExtensionObjectViewModel : ObservableObject
{

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