mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-21 21:51:51 +00:00
Compare commits
10 Commits
v1.17.1104
...
dev/miniks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5eb08ff804 | ||
|
|
7d0baa7946 | ||
|
|
a0e830cc1a | ||
|
|
a4cf4e2761 | ||
|
|
3dd40791c9 | ||
|
|
8f1960d0b4 | ||
|
|
65ada350ce | ||
|
|
3fb8a8be4b | ||
|
|
cd1c4b6b10 | ||
|
|
6cac0969f3 |
5
.github/actions/spelling/allow/apis.txt
vendored
5
.github/actions/spelling/allow/apis.txt
vendored
@@ -55,8 +55,6 @@ GETMOUSEHOVERTIME
|
||||
Hashtable
|
||||
HIGHCONTRASTON
|
||||
HIGHCONTRASTW
|
||||
hinternet
|
||||
HINTERNET
|
||||
hotkeys
|
||||
href
|
||||
hrgn
|
||||
@@ -216,8 +214,6 @@ Viewbox
|
||||
virtualalloc
|
||||
wcsstr
|
||||
wcstoui
|
||||
WDJ
|
||||
winhttp
|
||||
winmain
|
||||
winsta
|
||||
winstamin
|
||||
@@ -225,7 +221,6 @@ wmemcmp
|
||||
wpc
|
||||
WSF
|
||||
wsregex
|
||||
WWH
|
||||
wwinmain
|
||||
xchg
|
||||
XDocument
|
||||
|
||||
4
.github/actions/spelling/allow/microsoft.txt
vendored
4
.github/actions/spelling/allow/microsoft.txt
vendored
@@ -33,7 +33,6 @@ libucrtd
|
||||
LKG
|
||||
LOCKFILE
|
||||
Lxss
|
||||
makepri
|
||||
mfcribbon
|
||||
microsoft
|
||||
microsoftonline
|
||||
@@ -51,13 +50,10 @@ pgo
|
||||
pgosweep
|
||||
powerrename
|
||||
powershell
|
||||
priconfig
|
||||
PRIINFO
|
||||
propkey
|
||||
pscustomobject
|
||||
QWORD
|
||||
regedit
|
||||
resfiles
|
||||
robocopy
|
||||
SACLs
|
||||
segoe
|
||||
|
||||
7
.github/actions/spelling/expect/expect.txt
vendored
7
.github/actions/spelling/expect/expect.txt
vendored
@@ -257,7 +257,6 @@ condrv
|
||||
conechokey
|
||||
conemu
|
||||
configurability
|
||||
confusables
|
||||
conhost
|
||||
conime
|
||||
conimeinfo
|
||||
@@ -312,6 +311,7 @@ CPLINFO
|
||||
cplusplus
|
||||
CPPCORECHECK
|
||||
cppcorecheckrules
|
||||
cpprest
|
||||
cpprestsdk
|
||||
cppwinrt
|
||||
CProc
|
||||
@@ -1437,6 +1437,7 @@ PPEB
|
||||
ppf
|
||||
ppguid
|
||||
ppidl
|
||||
pplx
|
||||
PPROC
|
||||
PPROCESS
|
||||
ppropvar
|
||||
@@ -1576,7 +1577,6 @@ replatformed
|
||||
Replymessage
|
||||
repositorypath
|
||||
Requiresx
|
||||
rerasterize
|
||||
rescap
|
||||
Resequence
|
||||
RESETCONTENT
|
||||
@@ -1777,7 +1777,6 @@ srv
|
||||
srvinit
|
||||
srvpipe
|
||||
ssa
|
||||
startdir
|
||||
STARTF
|
||||
STARTUPINFO
|
||||
STARTUPINFOEX
|
||||
@@ -1951,7 +1950,6 @@ trx
|
||||
tsattrs
|
||||
tsf
|
||||
tsgr
|
||||
tsm
|
||||
TStr
|
||||
TSTRFORMAT
|
||||
TSub
|
||||
@@ -2116,6 +2114,7 @@ WDDMCONSOLECONTEXT
|
||||
wdm
|
||||
webpage
|
||||
websites
|
||||
websockets
|
||||
wekyb
|
||||
wex
|
||||
wextest
|
||||
|
||||
@@ -35,7 +35,7 @@ ROY\sG\.\sBIV
|
||||
# hit-count: 71 file-count: 35
|
||||
# Compiler flags
|
||||
(?:^|[\t ,"'`=(])-[D](?=[A-Z]{2,}|[A-Z][a-z])
|
||||
(?:^|[\t ,"'`=(])-[X](?!aml)(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
(?:^|[\t ,"'`=(])-[X](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
|
||||
# hit-count: 41 file-count: 28
|
||||
# version suffix <word>v#
|
||||
|
||||
@@ -326,9 +326,6 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winconpty.Tests.Feature", "src\winconpty\ft_pty\winconpty.FeatureTests.vcxproj", "{024052DE-83FB-4653-AEA4-90790D29D5BD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAzBridge", "src\cascadia\TerminalAzBridge\TerminalAzBridge.vcxproj", "{067F0A06-FCB7-472C-96E9-B03B54E8E18D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxproj", "{6BAE5851-50D5-4934-8D5E-30361A8A40F3}"
|
||||
EndProject
|
||||
|
||||
@@ -55,7 +55,14 @@ Copy-Item "build\helix\runtests.cmd" $payloadDir
|
||||
Copy-Item "build\helix\InstallTestAppDependencies.ps1" "$payloadDir"
|
||||
Copy-Item "build\Helix\EnsureMachineState.ps1" "$payloadDir"
|
||||
|
||||
# Extract the unpackaged distribution of Windows Terminal to the payload directory,
|
||||
# where it will create a subdirectory named terminal-0.0.1.0
|
||||
# This is referenced in TerminalApp.cs later as part of the test harness.
|
||||
& tar -x -v -f "$repoDirectory\Artifacts\$ArtifactName\unpackaged\WindowsTerminalDev_0.0.1.0_x64.zip" -C "$payloadDir"
|
||||
# Copy the APPX package from the 'drop' artifact dir and Windows Kits
|
||||
Copy-Item "$repoDirectory\Artifacts\$ArtifactName\appx\CascadiaPackage_0.0.1.0_$Platform.msix" $payloadDir\CascadiaPackage.zip
|
||||
Copy-Item "C:\program files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\Microsoft.VCLibs.Desktop\14.0\Appx\Retail\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx" $payloadDir\VCLibs.zip
|
||||
|
||||
# Rename it to extension of ZIP because Expand-Archive is real sassy on the build machines
|
||||
# and refuses to unzip it because of its file extension while on a desktop, it just
|
||||
# does the job without complaining.
|
||||
|
||||
# Extract the APPX package
|
||||
Expand-Archive -LiteralPath $payloadDir\CascadiaPackage.zip -DestinationPath $payloadDir\appx
|
||||
Expand-Archive -LiteralPath $payloadDir\VCLibs.zip -DestinationPath $payloadDir\appx -Force
|
||||
|
||||
@@ -70,7 +70,7 @@ foreach ($testRun in $testRuns.value)
|
||||
|
||||
foreach ($testResult in $testResults.value)
|
||||
{
|
||||
$info = ConvertFrom-Json ([System.Web.HttpUtility]::HtmlDecode($testResult.comment))
|
||||
$info = ConvertFrom-Json $testResult.comment
|
||||
$helixJobId = $info.HelixJobId
|
||||
$helixWorkItemName = $info.HelixWorkItemName
|
||||
|
||||
|
||||
@@ -67,6 +67,51 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
// THIRD PARTY SOFTWARE
|
||||
"MatchedPath": [
|
||||
"cpprest*.dll"
|
||||
],
|
||||
"SigningInfo": {
|
||||
"Operations": [
|
||||
{
|
||||
"KeyCode": "CP-231522",
|
||||
"OperationSetCode": "SigntoolSign",
|
||||
"Parameters": [
|
||||
{
|
||||
"parameterName": "OpusName",
|
||||
"parameterValue": "Microsoft"
|
||||
},
|
||||
{
|
||||
"parameterName": "OpusInfo",
|
||||
"parameterValue": "http://www.microsoft.com"
|
||||
},
|
||||
{
|
||||
"parameterName": "FileDigest",
|
||||
"parameterValue": "/fd \"SHA256\""
|
||||
},
|
||||
{
|
||||
"parameterName": "PageHash",
|
||||
"parameterValue": "/NPH"
|
||||
},
|
||||
{
|
||||
"parameterName": "TimeStamp",
|
||||
"parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||
}
|
||||
],
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
},
|
||||
{
|
||||
"KeyCode": "CP-231522",
|
||||
"OperationSetCode": "SigntoolVerify",
|
||||
"Parameters": [],
|
||||
"ToolName": "sign",
|
||||
"ToolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<package id="MUXCustomBuildTasks" version="1.0.48" targetFramework="native" />
|
||||
<package id="Microsoft.Taef" version="10.60.210621002" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
|
||||
<!-- This cannot be included in another project that depends on XAML (as it would be a duplicate package ID) -->
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
<package id="Microsoft.Debugging.Tools.PdbStr" version="20220617.1556.0" targetFramework="native" />
|
||||
<package id="Microsoft.Debugging.Tools.SrcTool" version="20220617.1556.0" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -56,10 +56,15 @@ parameters:
|
||||
- x64
|
||||
- x86
|
||||
- arm64
|
||||
- name: buildWindowsVersions
|
||||
type: object
|
||||
default:
|
||||
- Win10
|
||||
- Win11
|
||||
|
||||
variables:
|
||||
MakeAppxPath: 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\MakeAppx.exe'
|
||||
TerminalInternalPackageVersion: "0.0.8"
|
||||
TerminalInternalPackageVersion: "0.0.7"
|
||||
# If we are building a branch called "release-*", change the NuGet suffix
|
||||
# to "preview". If we don't do that, XES will set the suffix to "release1"
|
||||
# because it truncates the value after the first period.
|
||||
@@ -82,6 +87,13 @@ variables:
|
||||
NuGetPackBetaVersion: preview
|
||||
${{ elseif eq(variables['Build.SourceBranchName'], 'main') }}:
|
||||
NuGetPackBetaVersion: experimental
|
||||
# The NuGet packages have to use *somebody's* DLLs. We used to force them to
|
||||
# use the Win10 build outputs, but if there isn't a Win10 build we should use
|
||||
# the Win11 one.
|
||||
${{ if containsValue(parameters.buildWindowsVersions, 'Win10') }}:
|
||||
TerminalBestVersionForNuGetPackages: Win10
|
||||
${{ else }}:
|
||||
TerminalBestVersionForNuGetPackages: Win11
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
resources:
|
||||
@@ -95,9 +107,11 @@ jobs:
|
||||
matrix:
|
||||
${{ each config in parameters.buildConfigurations }}:
|
||||
${{ each platform in parameters.buildPlatforms }}:
|
||||
${{ config }}_${{ platform }}:
|
||||
BuildConfiguration: ${{ config }}
|
||||
BuildPlatform: ${{ platform }}
|
||||
${{ each windowsVersion in parameters.buildWindowsVersions }}:
|
||||
${{ config }}_${{ platform }}_${{ windowsVersion }}:
|
||||
BuildConfiguration: ${{ config }}
|
||||
BuildPlatform: ${{ platform }}
|
||||
TerminalTargetWindowsVersion: ${{ windowsVersion }}
|
||||
displayName: Build
|
||||
timeoutInMinutes: 240
|
||||
cancelTimeoutInMinutes: 1
|
||||
@@ -171,6 +185,10 @@ jobs:
|
||||
arguments: -MarkdownNoticePath .\NOTICE.md -OutputPath .\src\cascadia\CascadiaPackage\NOTICE.html
|
||||
pwsh: true
|
||||
- ${{ if eq(parameters.buildTerminal, true) }}:
|
||||
- pwsh: |-
|
||||
./build/scripts/Patch-ManifestsToWindowsVersion.ps1 -NewWindowsVersion "10.0.22000.0"
|
||||
displayName: Update manifest target version to Win11 (if necessary)
|
||||
condition: and(succeeded(), eq(variables['TerminalTargetWindowsVersion'], 'Win11'))
|
||||
- task: VSBuild@1
|
||||
displayName: Build solution **\OpenConsole.sln
|
||||
condition: true
|
||||
@@ -187,7 +205,7 @@ jobs:
|
||||
continueOnError: True
|
||||
inputs:
|
||||
PathtoPublish: $(Build.SourcesDirectory)\msbuild.binlog
|
||||
ArtifactName: binlog-$(BuildPlatform)
|
||||
ArtifactName: binlog-$(BuildPlatform)-$(TerminalTargetWindowsVersion)
|
||||
- task: PowerShell@2
|
||||
displayName: Check MSIX for common regressions
|
||||
inputs:
|
||||
@@ -236,12 +254,16 @@ jobs:
|
||||
arguments: -MatchPattern '*feature.test*.dll' -Platform '$(RationalizedBuildPlatform)' -Configuration '$(BuildConfiguration)'
|
||||
- ${{ if eq(parameters.buildTerminal, true) }}:
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy *.msix and symbols to Artifacts
|
||||
displayName: Copy *.appx/*.msix to Artifacts
|
||||
inputs:
|
||||
Contents: >-
|
||||
**/*.appx
|
||||
|
||||
**/*.msix
|
||||
|
||||
**/*.appxsym
|
||||
|
||||
!**/Microsoft.VCLibs*.appx
|
||||
TargetFolder: $(Build.ArtifactStagingDirectory)/appx
|
||||
OverWrite: true
|
||||
flattenFolders: true
|
||||
@@ -275,17 +297,7 @@ jobs:
|
||||
displayName: Publish Artifact (appx)
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)/appx
|
||||
ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)
|
||||
|
||||
- pwsh: |-
|
||||
$XamlAppxPath = (Get-Item "src\cascadia\CascadiaPackage\AppPackages\*\Dependencies\$(BuildPlatform)\Microsoft.UI.Xaml*.appx").FullName
|
||||
& .\build\scripts\New-UnpackagedTerminalDistribution.ps1 -TerminalAppX $(WindowsTerminalPackagePath) -XamlAppX $XamlAppxPath -Destination "$(Build.ArtifactStagingDirectory)/unpackaged"
|
||||
displayName: Build Unpackaged Distribution
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)/unpackaged
|
||||
artifact: unpackaged-$(BuildPlatform)-$(BuildConfiguration)
|
||||
displayName: Publish Artifact (unpackaged)
|
||||
|
||||
ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
|
||||
- ${{ if eq(parameters.buildConPTY, true) }}:
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy ConPTY to Artifacts
|
||||
@@ -303,7 +315,7 @@ jobs:
|
||||
displayName: Publish Artifact (ConPTY)
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)/conpty
|
||||
ArtifactName: conpty-dll-$(BuildPlatform)-$(BuildConfiguration)
|
||||
ArtifactName: conpty-dll-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
|
||||
- ${{ if eq(parameters.buildWPF, true) }}:
|
||||
- task: CopyFiles@2
|
||||
displayName: Copy PublicTerminalCore.dll to Artifacts
|
||||
@@ -317,7 +329,7 @@ jobs:
|
||||
displayName: Publish Artifact (PublicTerminalCore)
|
||||
inputs:
|
||||
PathtoPublish: $(Build.ArtifactStagingDirectory)/wpf
|
||||
ArtifactName: wpf-dll-$(BuildPlatform)-$(BuildConfiguration)
|
||||
ArtifactName: wpf-dll-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
|
||||
|
||||
- task: PublishSymbols@2
|
||||
displayName: Publish symbols path
|
||||
@@ -335,6 +347,11 @@ jobs:
|
||||
|
||||
- ${{ if eq(parameters.buildTerminal, true) }}:
|
||||
- job: BundleAndSign
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each windowsVersion in parameters.buildWindowsVersions }}:
|
||||
${{ windowsVersion }}:
|
||||
TerminalTargetWindowsVersion: ${{ windowsVersion }}
|
||||
displayName: Create and sign AppX/MSIX bundles
|
||||
variables:
|
||||
${{ if eq(parameters.branding, 'Release') }}:
|
||||
@@ -356,9 +373,9 @@ jobs:
|
||||
disableOutputRedirect: true
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download Artifacts ${{ platform }}
|
||||
displayName: Download Artifacts ${{ platform }} $(TerminalTargetWindowsVersion)
|
||||
inputs:
|
||||
artifactName: appx-${{ platform }}-Release
|
||||
artifactName: appx-${{ platform }}-Release-$(TerminalTargetWindowsVersion)
|
||||
# Add 3000 to the major version component, but only for the bundle.
|
||||
# This is to ensure that it is newer than "2022.xx.yy.zz" or whatever the original bundle versions were before
|
||||
# we switched to uniform naming.
|
||||
@@ -368,7 +385,7 @@ jobs:
|
||||
$Components[0] = ([int]$Components[0] + $VersionEpoch)
|
||||
$BundleVersion = $Components -Join "."
|
||||
New-Item -Type Directory "$(System.ArtifactsDirectory)\bundle"
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\bundle\$(BundleStemName)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
.\build\scripts\Create-AppxBundle.ps1 -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion $BundleVersion -OutputPath "$(System.ArtifactsDirectory)\bundle\$(BundleStemName)_$(TerminalTargetWindowsVersion)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
|
||||
displayName: Create WindowsTerminal*.msixbundle
|
||||
- task: EsrpCodeSigning@1
|
||||
displayName: Submit *.msixbundle to ESRP for code signing
|
||||
@@ -409,7 +426,7 @@ jobs:
|
||||
displayName: 'Publish Artifact: appxbundle-signed'
|
||||
inputs:
|
||||
PathtoPublish: $(System.ArtifactsDirectory)\bundle
|
||||
ArtifactName: appxbundle-signed
|
||||
ArtifactName: appxbundle-signed-$(TerminalTargetWindowsVersion)
|
||||
|
||||
- ${{ if eq(parameters.buildConPTY, true) }}:
|
||||
- job: PackageAndSignConPTY
|
||||
@@ -434,7 +451,7 @@ jobs:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download ${{ platform }} ConPTY binaries
|
||||
inputs:
|
||||
artifactName: conpty-dll-${{ platform }}-$(BuildConfiguration)
|
||||
artifactName: conpty-dll-${{ platform }}-$(BuildConfiguration)-$(TerminalBestVersionForNuGetPackages)
|
||||
downloadPath: bin\${{ platform }}\$(BuildConfiguration)\
|
||||
extractTars: false
|
||||
- task: PowerShell@2
|
||||
@@ -525,7 +542,7 @@ jobs:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download ${{ platform }} PublicTerminalCore
|
||||
inputs:
|
||||
artifactName: wpf-dll-${{ platform }}-$(BuildConfiguration)
|
||||
artifactName: wpf-dll-${{ platform }}-$(BuildConfiguration)-$(TerminalBestVersionForNuGetPackages)
|
||||
itemPattern: '**/*.dll'
|
||||
downloadPath: bin\${{ platform }}\$(BuildConfiguration)\
|
||||
extractTars: false
|
||||
@@ -623,10 +640,11 @@ jobs:
|
||||
|
||||
# Download the appx-PLATFORM-CONFIG-VERSION artifact for every platform/version combo
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download Symbols ${{ platform }}
|
||||
inputs:
|
||||
artifactName: appx-${{ platform }}-Release
|
||||
- ${{ each windowsVersion in parameters.buildWindowsVersions }}:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download Symbols ${{ platform }} ${{ windowsVersion }}
|
||||
inputs:
|
||||
artifactName: appx-${{ platform }}-Release-${{ windowsVersion }}
|
||||
|
||||
# It seems easier to do this -- download every appxsym -- then enumerate all the PDBs in the build directory for the
|
||||
# public symbol push. Otherwise, we would have to list all of the PDB files one by one.
|
||||
@@ -686,7 +704,7 @@ jobs:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download Build Artifacts
|
||||
inputs:
|
||||
artifactName: appxbundle-signed
|
||||
artifactName: appxbundle-signed-Win11
|
||||
extractTars: false
|
||||
- task: PowerShell@2
|
||||
displayName: Rename and stage packages for vpack
|
||||
@@ -695,7 +713,7 @@ jobs:
|
||||
script: >-
|
||||
# Rename to known/fixed name for Windows build system
|
||||
|
||||
Get-ChildItem Microsoft.WindowsTerminal_*.msixbundle | Rename-Item -NewName { 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle' }
|
||||
Get-ChildItem Microsoft.WindowsTerminal_Win11_*.msixbundle | Rename-Item -NewName { 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle' }
|
||||
|
||||
|
||||
# Create vpack directory and place item inside
|
||||
@@ -703,13 +721,13 @@ jobs:
|
||||
mkdir WindowsTerminal.app
|
||||
|
||||
mv Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle .\WindowsTerminal.app\
|
||||
workingDirectory: $(System.ArtifactsDirectory)\appxbundle-signed
|
||||
workingDirectory: $(System.ArtifactsDirectory)\appxbundle-signed-Win11
|
||||
- task: PkgESVPack@12
|
||||
displayName: 'Package ES - VPack'
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
inputs:
|
||||
sourceDirectory: $(System.ArtifactsDirectory)\appxbundle-signed\WindowsTerminal.app
|
||||
sourceDirectory: $(System.ArtifactsDirectory)\appxbundle-signed-Win11\WindowsTerminal.app
|
||||
description: VPack for the Windows Terminal Application
|
||||
pushPkgName: WindowsTerminal.app
|
||||
owner: conhost
|
||||
|
||||
@@ -144,7 +144,7 @@ jobs:
|
||||
inputs:
|
||||
TargetPattern: guardianGlob
|
||||
# See https://aka.ms/gdn-globs for how to do match patterns
|
||||
AnalyzeTargetGlob: $(Build.SourcesDirectory)\bin\**\*.dll;$(Build.SourcesDirectory)\bin\**\*.exe;-:file|**\Microsoft.UI.Xaml.dll;-:file|**\Microsoft.Toolkit.Win32.UI.XamlHost.dll;-:file|**\vcruntime*.dll;-:file|**\vcomp*.dll;-:file|**\vccorlib*.dll;-:file|**\vcamp*.dll;-:file|**\msvcp*.dll;-:file|**\concrt*.dll;-:file|**\TerminalThemeHelpers*.dll
|
||||
AnalyzeTargetGlob: $(Build.SourcesDirectory)\bin\**\*.dll;$(Build.SourcesDirectory)\bin\**\*.exe;-:file|**\Microsoft.UI.Xaml.dll;-:file|**\Microsoft.Toolkit.Win32.UI.XamlHost.dll;-:file|**\vcruntime*.dll;-:file|**\vcomp*.dll;-:file|**\vccorlib*.dll;-:file|**\vcamp*.dll;-:file|**\msvcp*.dll;-:file|**\concrt*.dll;-:file|**\TerminalThemeHelpers*.dll;-:file|**\cpprest*.dll
|
||||
continueOnError: true
|
||||
|
||||
# Set XES_SERIALPOSTBUILDREADY to run Security and Compliance task once per build
|
||||
|
||||
@@ -64,24 +64,17 @@ steps:
|
||||
Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy *.msix to Artifacts'
|
||||
displayName: 'Copy *.appx/*.msix to Artifacts (Non-PR builds only)'
|
||||
inputs:
|
||||
Contents: |
|
||||
**/*.appx
|
||||
**/*.msix
|
||||
**/*.appxsym
|
||||
!**/Microsoft.VCLibs*.appx
|
||||
TargetFolder: '$(Build.ArtifactStagingDirectory)/appx'
|
||||
OverWrite: true
|
||||
flattenFolders: true
|
||||
|
||||
- pwsh: |-
|
||||
$TerminalMsixPath = (Get-Item "$(Build.ArtifactStagingDirectory)\appx\Cascadia*.msix").FullName
|
||||
$XamlAppxPath = (Get-Item "src\cascadia\CascadiaPackage\AppPackages\*\Dependencies\$(BuildPlatform)\Microsoft.UI.Xaml*.appx").FullName
|
||||
& .\build\scripts\New-UnpackagedTerminalDistribution.ps1 -TerminalAppX $TerminalMsixPath -XamlAppX $XamlAppxPath -Destination "$(Build.ArtifactStagingDirectory)/unpackaged"
|
||||
displayName: Build Unpackaged Distribution
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)/unpackaged
|
||||
artifact: unpackaged-$(BuildPlatform)-$(BuildConfiguration)
|
||||
displayName: Publish Artifact (unpackaged)
|
||||
condition: succeeded()
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy outputs needed for test runs to Artifacts'
|
||||
|
||||
@@ -14,8 +14,8 @@ parameters:
|
||||
platform: ''
|
||||
# if 'useBuildOutputFromBuildId' is set, we will default to using a build from this pipeline:
|
||||
useBuildOutputFromPipeline: $(System.DefinitionId)
|
||||
openHelixTargetQueues: 'windows.11.amd64.client.open.reunion'
|
||||
closedHelixTargetQueues: 'windows.11.amd64.client.reunion'
|
||||
openHelixTargetQueues: 'windows.10.amd64.client21h1.open.xaml'
|
||||
closedHelixTargetQueues: 'windows.10.amd64.client21h1.xaml'
|
||||
|
||||
jobs:
|
||||
- job: ${{ parameters.name }}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
Param(
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="List of PRI files or XML dumps (detailed only) to merge")]
|
||||
[string[]]
|
||||
$Path,
|
||||
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Output Path")]
|
||||
[string]
|
||||
$OutputPath,
|
||||
|
||||
[Parameter(HelpMessage="Name of index in output file; defaults to 'Application'")]
|
||||
[string]
|
||||
$IndexName = "Application",
|
||||
|
||||
[Parameter(HelpMessage="Path to makepri.exe")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$MakePriPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\MakePri.exe"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$tempDir = Join-Path ([System.IO.Path]::GetTempPath()) "tmp$([Convert]::ToString((Get-Random 65535),16).PadLeft(4,'0')).tmp"
|
||||
New-Item -ItemType Directory -Path $tempDir | Out-Null
|
||||
$priConfig = Join-Path $tempDir "priconfig.xml"
|
||||
$priListFile = Join-Path $tempDir "pri.resfiles"
|
||||
$dumpListFile = Join-Path $tempDir "dump.resfiles"
|
||||
|
||||
@"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources targetOsVersion="10.0.0" majorVersion="1">
|
||||
<index root="\" startIndexAt="dump.resfiles">
|
||||
<default>
|
||||
<qualifier name="Language" value="en-US" />
|
||||
<qualifier name="Contrast" value="standard" />
|
||||
<qualifier name="Scale" value="200" />
|
||||
<qualifier name="HomeRegion" value="001" />
|
||||
<qualifier name="TargetSize" value="256" />
|
||||
<qualifier name="LayoutDirection" value="LTR" />
|
||||
<qualifier name="DXFeatureLevel" value="DX9" />
|
||||
<qualifier name="Configuration" value="" />
|
||||
<qualifier name="AlternateForm" value="" />
|
||||
<qualifier name="Platform" value="UAP" />
|
||||
</default>
|
||||
<indexer-config type="PRIINFO" />
|
||||
<indexer-config type="RESFILES" qualifierDelimiter="." />
|
||||
</index>
|
||||
<index root="\" startIndexAt="pri.resfiles">
|
||||
<default>
|
||||
<qualifier name="Language" value="en-US" />
|
||||
<qualifier name="Contrast" value="standard" />
|
||||
<qualifier name="Scale" value="200" />
|
||||
<qualifier name="HomeRegion" value="001" />
|
||||
<qualifier name="TargetSize" value="256" />
|
||||
<qualifier name="LayoutDirection" value="LTR" />
|
||||
<qualifier name="DXFeatureLevel" value="DX9" />
|
||||
<qualifier name="Configuration" value="" />
|
||||
<qualifier name="AlternateForm" value="" />
|
||||
<qualifier name="Platform" value="UAP" />
|
||||
</default>
|
||||
<indexer-config type="PRI" />
|
||||
<indexer-config type="RESFILES" qualifierDelimiter="." />
|
||||
</index>
|
||||
</resources>
|
||||
"@ | Out-File -Encoding:utf8NoBOM $priConfig
|
||||
|
||||
$Path | Where { $_ -Like "*.pri" } | ForEach-Object {
|
||||
Get-Item $_ | Select -Expand FullName
|
||||
} | Out-File -Encoding:utf8NoBOM $priListFile
|
||||
|
||||
$Path | Where { $_ -Like "*.xml" } | ForEach-Object {
|
||||
Get-Item $_ | Select -Expand FullName
|
||||
} | Out-File -Encoding:utf8NoBOM $dumpListFile
|
||||
|
||||
& $MakePriPath new /pr $tempDir /cf $priConfig /o /in $IndexName /of $OutputPath
|
||||
|
||||
Remove-Item -Recurse -Force $tempDir
|
||||
@@ -1,47 +0,0 @@
|
||||
Param(
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Root directory of extracted Terminal AppX")]
|
||||
[string[]]
|
||||
$TerminalRoot,
|
||||
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Root directory of extracted Xaml AppX")]
|
||||
[string[]]
|
||||
$XamlRoot,
|
||||
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Output Path")]
|
||||
[string]
|
||||
$OutputPath,
|
||||
|
||||
[Parameter(HelpMessage="Path to makepri.exe")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$MakePriPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\MakePri.exe"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$tempDir = Join-Path ([System.IO.Path]::GetTempPath()) "tmp$([Convert]::ToString((Get-Random 65535),16).PadLeft(4,'0')).tmp"
|
||||
New-Item -ItemType Directory -Path $tempDir | Out-Null
|
||||
|
||||
$terminalDump = Join-Path $tempDir "terminal.pri.xml"
|
||||
|
||||
& $MakePriPath dump /if (Join-Path $TerminalRoot "resources.pri") /of $terminalDump /dt detailed
|
||||
|
||||
Write-Verbose "Removing Microsoft.UI.Xaml node from Terminal to prevent a collision with XAML"
|
||||
$terminalXMLDocument = [xml](Get-Content $terminalDump)
|
||||
$resourceMap = $terminalXMLDocument.PriInfo.ResourceMap
|
||||
$fileSubtree = $resourceMap.ResourceMapSubtree | Where-Object { $_.Name -eq "Files" }
|
||||
$subtrees = $fileSubtree.ResourceMapSubtree
|
||||
$xamlSubtreeChild = ($subtrees | Where-Object { $_.Name -eq "Microsoft.UI.Xaml" })
|
||||
if ($Null -Ne $xamlSubtreeChild) {
|
||||
$null = $fileSubtree.RemoveChild($xamlSubtreeChild)
|
||||
$terminalXMLDocument.Save($terminalDump)
|
||||
}
|
||||
|
||||
$indexName = $terminalXMLDocument.PriInfo.ResourceMap.name
|
||||
|
||||
& (Join-Path $PSScriptRoot "Merge-PriFiles.ps1") -Path $terminalDump, (Join-Path $XamlRoot "resources.pri") -IndexName $indexName -OutputPath $OutputPath -MakePriPath $MakePriPath
|
||||
|
||||
Remove-Item -Recurse -Force $tempDir
|
||||
@@ -1,117 +0,0 @@
|
||||
Param(
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Path to Terminal AppX")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$TerminalAppX,
|
||||
|
||||
[Parameter(Mandatory,
|
||||
HelpMessage="Path to Xaml AppX")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$XamlAppX,
|
||||
|
||||
[Parameter(HelpMessage="Output Directory")]
|
||||
[string]
|
||||
$Destination = ".",
|
||||
|
||||
[Parameter(HelpMessage="Path to makeappx.exe")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\MakeAppx.exe"
|
||||
)
|
||||
|
||||
$filesToRemove = @("*.xml", "*.winmd", "Appx*", "Images/*Tile*", "Images/*Logo*") # Remove from Terminal
|
||||
$filesToKeep = @("Microsoft.Terminal.Remoting.winmd") # ... except for these
|
||||
$filesToCopyFromXaml = @("Microsoft.UI.Xaml.dll", "Microsoft.UI.Xaml") # We don't need the .winmd
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
If ($null -Eq (Get-Item $MakeAppxPath -EA:SilentlyContinue)) {
|
||||
Write-Error "Could not find MakeAppx.exe at `"$MakeAppxPath`".`nMake sure that -MakeAppxPath points to a valid SDK."
|
||||
Exit 1
|
||||
}
|
||||
|
||||
$tempDir = Join-Path ([System.IO.Path]::GetTempPath()) "tmp$([Convert]::ToString((Get-Random 65535),16).PadLeft(4,'0')).tmp"
|
||||
New-Item -ItemType Directory -Path $tempDir | Out-Null
|
||||
|
||||
$XamlAppX = Get-Item $XamlAppX | Select-Object -Expand FullName
|
||||
$TerminalAppX = Get-Item $TerminalAppX | Select-Object -Expand FullName
|
||||
|
||||
########
|
||||
# Reading the AppX Manifest for preliminary info
|
||||
########
|
||||
|
||||
$appxManifestPath = Join-Path $tempDir AppxManifest.xml
|
||||
& tar.exe -x -f "$TerminalAppX" -C $tempDir AppxManifest.xml
|
||||
$manifest = [xml](Get-Content $appxManifestPath)
|
||||
$pfn = $manifest.Package.Identity.Name
|
||||
$version = $manifest.Package.Identity.Version
|
||||
$architecture = $manifest.Package.Identity.ProcessorArchitecture
|
||||
|
||||
$distributionName = "{0}_{1}_{2}" -f ($pfn, $version, $architecture)
|
||||
$terminalDir = "terminal-{0}" -f ($version)
|
||||
|
||||
########
|
||||
# Unpacking Terminal and XAML
|
||||
########
|
||||
|
||||
$terminalAppPath = Join-Path $tempdir $terminalDir
|
||||
$xamlAppPath = Join-Path $tempdir "xaml"
|
||||
New-Item -ItemType Directory -Path $terminalAppPath | Out-Null
|
||||
New-Item -ItemType Directory -Path $xamlAppPath | Out-Null
|
||||
& $MakeAppxPath unpack /p $TerminalAppX /d $terminalAppPath /o | Out-Null
|
||||
If ($LASTEXITCODE -Ne 0) {
|
||||
Throw "Unpacking $TerminalAppX failed"
|
||||
}
|
||||
& $MakeAppxPath unpack /p $XamlAppX /d $xamlAppPath /o | Out-Null
|
||||
If ($LASTEXITCODE -Ne 0) {
|
||||
Throw "Unpacking $XamlAppX failed"
|
||||
}
|
||||
|
||||
########
|
||||
# Some sanity checking
|
||||
########
|
||||
|
||||
$xamlManifest = [xml](Get-Content (Join-Path $xamlAppPath "AppxManifest.xml"))
|
||||
If ($xamlManifest.Package.Identity.Name -NotLike "Microsoft.UI.Xaml*") {
|
||||
Throw "$XamlAppX is not a XAML package (instead, it looks like $($xamlManifest.Package.Identity.Name))"
|
||||
}
|
||||
If ($xamlManifest.Package.Identity.ProcessorArchitecture -Ne $architecture) {
|
||||
Throw "$XamlAppX is not built for $architecture (instead, it is built for $($xamlManifest.Package.Identity.ProcessorArchitecture))"
|
||||
}
|
||||
|
||||
########
|
||||
# Preparation of source files
|
||||
########
|
||||
|
||||
$itemsToRemove = $filesToRemove | ForEach-Object {
|
||||
Get-Item (Join-Path $terminalAppPath $_) -EA:SilentlyContinue | Where-Object {
|
||||
$filesToKeep -NotContains $_.Name
|
||||
}
|
||||
} | Sort-Object FullName -Unique
|
||||
$itemsToRemove | Remove-Item -Recurse
|
||||
|
||||
$filesToCopyFromXaml | ForEach-Object {
|
||||
Get-Item (Join-Path $xamlAppPath $_)
|
||||
} | Copy-Item -Recurse -Destination $terminalAppPath
|
||||
|
||||
########
|
||||
# Resource Management
|
||||
########
|
||||
|
||||
$finalTerminalPriFile = Join-Path $terminalAppPath "resources.pri"
|
||||
& (Join-Path $PSScriptRoot "Merge-TerminalAndXamlResources.ps1") `
|
||||
-TerminalRoot $terminalAppPath `
|
||||
-XamlRoot $xamlAppPath `
|
||||
-OutputPath $finalTerminalPriFile `
|
||||
-Verbose:$Verbose
|
||||
|
||||
########
|
||||
# Packaging
|
||||
########
|
||||
|
||||
New-Item -ItemType Directory -Path $Destination -ErrorAction:SilentlyContinue | Out-Null
|
||||
$outputZip = (Join-Path $Destination ("{0}.zip" -f ($distributionName)))
|
||||
& tar -c --format=zip -f $outputZip -C $tempDir $terminalDir
|
||||
Get-Item $outputZip
|
||||
14
build/scripts/Patch-ManifestsToWindowsVersion.ps1
Normal file
14
build/scripts/Patch-ManifestsToWindowsVersion.ps1
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
Param(
|
||||
[string]$NewWindowsVersion = "10.0.22000.0"
|
||||
)
|
||||
|
||||
Get-ChildItem src/cascadia/CascadiaPackage -Recurse -Filter *.appxmanifest | ForEach-Object {
|
||||
$xml = [xml](Get-Content $_.FullName)
|
||||
$xml.Package.Dependencies.TargetDeviceFamily | Where-Object Name -Like "Windows*" | ForEach-Object {
|
||||
$_.MinVersion = $NewWindowsVersion
|
||||
}
|
||||
$xml.Save($_.FullName)
|
||||
}
|
||||
@@ -96,6 +96,11 @@ Try {
|
||||
Throw "Failed to find App.xbf (TerminalApp project) in resources.pri"
|
||||
}
|
||||
|
||||
If (($null -eq (Get-Item "$AppxPackageRootPath\cpprest142_2_10.dll" -EA:Ignore)) -And
|
||||
($null -eq (Get-Item "$AppxPackageRootPath\cpprest142_2_10d.dll" -EA:Ignore))) {
|
||||
Throw "Failed to find cpprest142_2_10.dll -- check the WAP packaging project"
|
||||
}
|
||||
|
||||
If (($null -eq (Get-Item "$AppxPackageRootPath\wtd.exe" -EA:Ignore)) -And
|
||||
($null -eq (Get-Item "$AppxPackageRootPath\wt.exe" -EA:Ignore))) {
|
||||
Throw "Failed to find wt.exe/wtd.exe -- check the WAP packaging project"
|
||||
|
||||
@@ -10,4 +10,22 @@
|
||||
<OpenConsoleDir>$(MSBuildThisFileDirectory)</OpenConsoleDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
For the Windows 10 build, we're targeting the prerelease version of Microsoft.UI.Xaml.
|
||||
This version emits every XAML DLL directly into our package.
|
||||
This is a workaround for us not having deliverable MSFT-21242953 on this version of Windows.
|
||||
|
||||
This version should be tracked in all project packages.config files for projects that depend on Xaml.
|
||||
-->
|
||||
<TerminalMUXVersion>2.7.3-prerelease.220816001</TerminalMUXVersion>
|
||||
<!--
|
||||
For the Windows 11-specific build, we're targeting the public version of Microsoft.UI.Xaml.
|
||||
This version emits a package dependency instead of embedding the dependency in our own package.
|
||||
|
||||
This version should be tracked in build/packages.config.
|
||||
-->
|
||||
<TerminalMUXVersion Condition="'$(TerminalTargetWindowsVersion)'=='Win11'">2.7.3</TerminalMUXVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
16
custom.props
16
custom.props
@@ -2,10 +2,22 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!-- This file is read by XES, which we use in our Release builds. -->
|
||||
<PropertyGroup Label="Version">
|
||||
<!--
|
||||
The Windows 11 build is going to have the same package name, so it *must* have a different version.
|
||||
The easiest way for us to do this is to add 1 to the revision field.
|
||||
In short, for a given Terminal build 1.11, we will emit two different versions (assume this is build
|
||||
4 on day 23 of the year):
|
||||
- 1.11.234.0 for Windows 10
|
||||
- 1.11.235.0 for Windows 11
|
||||
This presents a potential for conflicts if we want to ship two builds produced back to back on the
|
||||
same day... which is terribly unlikely.
|
||||
-->
|
||||
<VersionBuildRevision Condition="'$(TerminalTargetWindowsVersion)'=='Win11' and '$(VersionBuildRevision)'!=''">$([MSBuild]::Add($(VersionBuildRevision), 1))</VersionBuildRevision>
|
||||
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2022</XesBaseYearForStoreVersion>
|
||||
<XesBaseYearForStoreVersion>2023</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>17</VersionMinor>
|
||||
<VersionMinor>18</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
|
||||
<package id="Microsoft.Taef" version="10.60.210621002" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
|
||||
<package id="vcpkg-cpprestsdk" version="2.10.14" targetFramework="native" />
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.6.220404001" targetFramework="native" />
|
||||
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3-prerelease.220816001" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220201.1" targetFramework="native" developmentDependency="true" />
|
||||
|
||||
<!-- Managed packages -->
|
||||
|
||||
@@ -6,14 +6,14 @@ SamplerState samplerState;
|
||||
|
||||
// Terminal settings such as the resolution of the texture
|
||||
cbuffer PixelShaderSettings {
|
||||
// The number of seconds since the pixel shader was enabled
|
||||
float Time;
|
||||
// UI Scale
|
||||
float Scale;
|
||||
// Resolution of the shaderTexture
|
||||
float2 Resolution;
|
||||
// Background color as rgba
|
||||
float4 Background;
|
||||
// The number of seconds since the pixel shader was enabled
|
||||
float Time;
|
||||
// UI Scale
|
||||
float Scale;
|
||||
// Resolution of the shaderTexture
|
||||
float2 Resolution;
|
||||
// Background color as rgba
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
// A pixel shader is a program that given a texture coordinate (tex) produces a color.
|
||||
@@ -29,19 +29,38 @@ float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
// effect, read the colors offset on the left, right, top, bottom of this
|
||||
// fragment, as well as on the corners of this fragment.
|
||||
//
|
||||
// You could get away with fewer samples, but the resulting outlines will be
|
||||
// blurrier.
|
||||
|
||||
//left, right, top, bottom:
|
||||
float4 leftColor = shaderTexture.Sample(samplerState, tex+1.0*Scale*float2( 1.0, 0.0)/Resolution.y);
|
||||
float4 rightColor = shaderTexture.Sample(samplerState, tex+1.0*Scale*float2(-1.0, 0.0)/Resolution.y);
|
||||
float4 topColor = shaderTexture.Sample(samplerState, tex+1.0*Scale*float2( 0.0, 1.0)/Resolution.y);
|
||||
float4 bottomColor = shaderTexture.Sample(samplerState, tex+1.0*Scale*float2( 0.0, -1.0)/Resolution.y);
|
||||
|
||||
// Corners
|
||||
float4 topLeftColor = shaderTexture.Sample(samplerState, tex+1.0*Scale*float2( 1.0, 1.0)/Resolution.y);
|
||||
float4 topRightColor = shaderTexture.Sample(samplerState, tex+1.0*Scale*float2(-1.0, 1.0)/Resolution.y);
|
||||
float4 bottomLeftColor = shaderTexture.Sample(samplerState, tex+1.0*Scale*float2( 1.0, -1.0)/Resolution.y);
|
||||
float4 bottomRightColor = shaderTexture.Sample(samplerState, tex+1.0*Scale*float2(-1.0, -1.0)/Resolution.y);
|
||||
|
||||
|
||||
// Now, if any of those adjacent cells has text in it, then the *color vec4
|
||||
// will have a non-zero .w (which is used for alpha). Use that alpha value
|
||||
// to add some black to the current fragment.
|
||||
//
|
||||
// This will result in only coloring fragments adjacent to text, but leaving
|
||||
// background images (for example) untouched.
|
||||
float3 outlineColor = float3(0, 0, 0);
|
||||
float4 result = color;
|
||||
result = result + float4(outlineColor, leftColor.w);
|
||||
result = result + float4(outlineColor, rightColor.w);
|
||||
result = result + float4(outlineColor, topColor.w);
|
||||
result = result + float4(outlineColor, bottomColor.w);
|
||||
|
||||
for (int dy = -2; dy <= 2; dy += 2) {
|
||||
for (int dx = -2; dx <= 2; dx += 2) {
|
||||
float4 neighbor = shaderTexture.Sample(samplerState, tex, int2(dx, dy));
|
||||
color.a += neighbor.a;
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
result = result + float4(outlineColor, topLeftColor.w);
|
||||
result = result + float4(outlineColor, topRightColor.w);
|
||||
result = result + float4(outlineColor, bottomLeftColor.w);
|
||||
result = result + float4(outlineColor, bottomRightColor.w);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -197,6 +197,26 @@
|
||||
<!-- **END VC LIBS HACK** -->
|
||||
|
||||
|
||||
<!-- **BEGIN TERMINAL CONNECTION HACK** -->
|
||||
<!-- This is the same as the above VC libs hack, but for TerminalConnection.
|
||||
TerminalConnection depends on cpprest*.dll, and if we don't include it in
|
||||
the packaging output, we'll crash as soon as we try to load
|
||||
TerminalConnection.dll.
|
||||
|
||||
The Sample sln needs to do this manually - the real exe has a
|
||||
ProjectReference to TerminalConnection.vcxproj and can figure this out on
|
||||
its own. -->
|
||||
<ItemGroup>
|
||||
<_TerminalConnectionDlls Include="$(OpenConsoleCommonOutDir)\TerminalConnection\*.dll" />
|
||||
|
||||
<PackagingOutputs Include="@(_TerminalConnectionDlls)">
|
||||
<ProjectName>$(ProjectName)</ProjectName>
|
||||
<OutputGroup>BuiltProjectOutputGroup</OutputGroup>
|
||||
<TargetPath>%(Filename)%(Extension)</TargetPath>
|
||||
</PackagingOutputs>
|
||||
</ItemGroup>
|
||||
<!-- **END TERMINAL CONNECTION HACK** -->
|
||||
|
||||
<!-- Same thing again here, with WindowsTerminal.exe -->
|
||||
<ItemGroup>
|
||||
<_WindowsTerminalExe Include="$(OpenConsoleCommonOutDir)\WindowsTerminal\*.exe" />
|
||||
|
||||
@@ -198,11 +198,6 @@ OutputCellIterator::operator bool() const noexcept
|
||||
CATCH_FAIL_FAST();
|
||||
}
|
||||
|
||||
size_t OutputCellIterator::Position() const noexcept
|
||||
{
|
||||
return _pos;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Advances the iterator one position over the underlying data source.
|
||||
// Return Value:
|
||||
|
||||
@@ -48,7 +48,6 @@ public:
|
||||
|
||||
operator bool() const noexcept;
|
||||
|
||||
size_t Position() const noexcept;
|
||||
til::CoordType GetCellDistance(OutputCellIterator other) const noexcept;
|
||||
til::CoordType GetInputDistance(OutputCellIterator other) const noexcept;
|
||||
friend til::CoordType operator-(OutputCellIterator one, OutputCellIterator two) = delete;
|
||||
|
||||
@@ -311,20 +311,16 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType c
|
||||
}
|
||||
break;
|
||||
case DbcsAttribute::Trailing:
|
||||
// Handling the trailing half of wide chars ensures that we correctly restore
|
||||
// wide characters when a user backs up and restores the viewport via CHAR_INFOs.
|
||||
if (fillingFirstColumn)
|
||||
{
|
||||
// The wide char doesn't fit. Pad with whitespace.
|
||||
// Ignore the character. There's no correct alternative way to handle this situation.
|
||||
ClearCell(currentIndex);
|
||||
}
|
||||
else if (it.Position() == 0)
|
||||
else
|
||||
{
|
||||
// A common way to back up and restore the buffer is via `ReadConsoleOutputW` and
|
||||
// `WriteConsoleOutputW` respectively. But the area might bisect/intersect/clip wide characters and
|
||||
// only backup either their leading or trailing half. In general, in the rest of conhost, we're
|
||||
// throwing away the trailing half of all `CHAR_INFO`s (during text rendering, as well as during
|
||||
// `ReadConsoleOutputW`), so to make this code behave the same and prevent surprises, we need to
|
||||
// make sure to only look at the trailer if it's the first `CHAR_INFO` the user is trying to write.
|
||||
ReplaceCharacters(currentIndex - 1, 2, chars);
|
||||
}
|
||||
++it;
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
|
||||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
|
||||
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
|
||||
IgnorableNamespaces="uap mp rescap uap3">
|
||||
|
||||
<Identity
|
||||
Name="WindowsTerminalDev"
|
||||
@@ -25,14 +23,6 @@
|
||||
<DisplayName>ms-resource:AppStoreNameDev</DisplayName>
|
||||
<PublisherDisplayName>A Lone Developer</PublisherDisplayName>
|
||||
<Logo>Images\StoreLogo.png</Logo>
|
||||
<!-- Older versions of Windows 10 respect this -->
|
||||
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||
<!-- Newer versions of Windows 10 plus all versions of Windows 11 respect this -->
|
||||
<virtualization:RegistryWriteVirtualization>
|
||||
<virtualization:ExcludedKeys>
|
||||
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
|
||||
</virtualization:ExcludedKeys>
|
||||
</virtualization:RegistryWriteVirtualization>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
@@ -146,6 +136,5 @@
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="unvirtualizedResources" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
|
||||
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
|
||||
IgnorableNamespaces="uap mp rescap uap3">
|
||||
|
||||
<Identity
|
||||
Name="Microsoft.WindowsTerminalPreview"
|
||||
@@ -26,14 +24,6 @@
|
||||
<DisplayName>ms-resource:AppStoreNamePre</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>Images\StoreLogo.png</Logo>
|
||||
<!-- Older versions of Windows 10 respect this -->
|
||||
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||
<!-- Newer versions of Windows 10 plus all versions of Windows 11 respect this -->
|
||||
<virtualization:RegistryWriteVirtualization>
|
||||
<virtualization:ExcludedKeys>
|
||||
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
|
||||
</virtualization:ExcludedKeys>
|
||||
</virtualization:RegistryWriteVirtualization>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
@@ -235,7 +225,6 @@
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="unvirtualizedResources" />
|
||||
</Capabilities>
|
||||
|
||||
<Extensions>
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
|
||||
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
|
||||
IgnorableNamespaces="uap mp rescap uap3">
|
||||
|
||||
<Identity
|
||||
Name="Microsoft.WindowsTerminal"
|
||||
@@ -26,14 +24,6 @@
|
||||
<DisplayName>ms-resource:AppStoreName</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>Images\StoreLogo.png</Logo>
|
||||
<!-- Older versions of Windows 10 respect this -->
|
||||
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||
<!-- Newer versions of Windows 10 plus all versions of Windows 11 respect this -->
|
||||
<virtualization:RegistryWriteVirtualization>
|
||||
<virtualization:ExcludedKeys>
|
||||
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
|
||||
</virtualization:ExcludedKeys>
|
||||
</virtualization:RegistryWriteVirtualization>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
@@ -235,7 +225,6 @@
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="unvirtualizedResources" />
|
||||
</Capabilities>
|
||||
|
||||
<Extensions>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<OpenConsoleCppWinRTProject>true</OpenConsoleCppWinRTProject>
|
||||
<!-- TerminalCppWinrt is not set intentionally -->
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(SolutionDir)\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
@@ -100,4 +99,15 @@
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.tests.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- From Microsoft.UI.Xaml.targets -->
|
||||
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
|
||||
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
|
||||
<_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\runtimes\win10-$(Native-Platform)\native\"</_MUXBinRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- We actually can just straight up reference MUX here, it's fine -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<!-- TerminalCppWinrt is intentionally not set -->
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(SolutionDir)\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
@@ -86,4 +85,15 @@
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.tests.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- From Microsoft.UI.Xaml.targets -->
|
||||
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
|
||||
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
|
||||
<_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\runtimes\win10-$(Native-Platform)\native\"</_MUXBinRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- We actually can just straight up reference MUX here, it's fine -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
<UseWmXml>true</UseWmXml>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<OpenConsoleCppWinRTProject>true</OpenConsoleCppWinRTProject>
|
||||
<EnableHybridCRT>false</EnableHybridCRT> <!-- C++/CLI projects can't deal -->
|
||||
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
|
||||
<!--
|
||||
These two properties are very important!
|
||||
@@ -128,6 +125,8 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
||||
<Import Project="$(OpenConsoleDir)\src\common.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)\src\common.nugetversions.targets" />
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ HRESULT HwndTerminal::Initialize()
|
||||
|
||||
_renderEngine = std::move(dxEngine);
|
||||
|
||||
_terminal->Create({ 80, 25 }, 9001, *_renderer);
|
||||
_terminal->Create({ 80, 25 }, 1000, *_renderer);
|
||||
_terminal->SetWriteInputCallback([=](std::wstring_view input) noexcept { _WriteTextToConnection(input); });
|
||||
localPointerToThread->EnablePainting();
|
||||
|
||||
|
||||
@@ -60,4 +60,4 @@
|
||||
<AdditionalDependencies>Uiautomationcore.lib;onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -300,6 +300,7 @@
|
||||
<PRIResource Include="Resources\en-US\Resources.resw" />
|
||||
<PRIResource Include="Resources\en-US\ContextMenu.resw" />
|
||||
<OCResourceDirectory Include="Resources" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1247,17 +1247,10 @@ namespace winrt::TerminalApp::implementation
|
||||
if (connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
|
||||
TerminalConnection::AzureConnection::IsAzureConnectionAvailable())
|
||||
{
|
||||
// TODO GH#4661: Replace this with directly using the AzCon when our VT is better
|
||||
std::filesystem::path azBridgePath{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
|
||||
azBridgePath.replace_filename(L"TerminalAzBridge.exe");
|
||||
if constexpr (Feature_AzureConnectionInProc::IsEnabled())
|
||||
{
|
||||
connection = TerminalConnection::AzureConnection{};
|
||||
}
|
||||
else
|
||||
{
|
||||
connection = TerminalConnection::ConptyConnection{};
|
||||
}
|
||||
|
||||
connection = TerminalConnection::ConptyConnection();
|
||||
auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.wstring(),
|
||||
L".",
|
||||
L"Azure",
|
||||
@@ -2473,27 +2466,14 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// GH#10188: WSL paths are okay. We'll let those through.
|
||||
if (host == L"wsl$" || host == L"wsl.localhost")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: by the OSC 8 spec, if a hostname (other than localhost) is provided, we _should_ be
|
||||
// comparing that value against what is returned by GetComputerNameExW and making sure they match.
|
||||
// However, ShellExecute does not seem to be happy with file URIs of the form
|
||||
// file://{hostname}/path/to/file.ext
|
||||
// and so while we could do the hostname matching, we do not know how to actually open the URI
|
||||
// if its given in that form. So for now we ignore all hostnames other than localhost
|
||||
return false;
|
||||
}
|
||||
|
||||
// In this case, the app manually output a URI other than file:// or
|
||||
// http(s)://. We'll trust the user knows what they're doing when
|
||||
// clicking on those sorts of links.
|
||||
// See discussion in GH#7562 for more details.
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Important! Don't take this eventArgs by reference, we need to extend the
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
#define DECLARE_ACTION_HANDLER(action) void _Handle##action(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
|
||||
static constexpr uint32_t DefaultRowsToScroll{ 3 };
|
||||
static constexpr std::wstring_view TabletInputServiceKey{ L"TabletInputService" };
|
||||
|
||||
namespace TerminalAppLocalTests
|
||||
{
|
||||
class TabTests;
|
||||
@@ -25,9 +28,6 @@ namespace Microsoft::Terminal::Core
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
inline constexpr uint32_t DefaultRowsToScroll{ 3 };
|
||||
inline constexpr std::wstring_view TabletInputServiceKey{ L"TabletInputService" };
|
||||
|
||||
enum StartupState : int
|
||||
{
|
||||
NotInitialized = 0,
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include "TabBase.h"
|
||||
#include "TerminalTab.g.h"
|
||||
|
||||
static constexpr double HeaderRenameBoxWidthDefault{ 165 };
|
||||
static constexpr double HeaderRenameBoxWidthTitleLength{ std::numeric_limits<double>::infinity() };
|
||||
|
||||
// fwdecl unittest classes
|
||||
namespace TerminalAppLocalTests
|
||||
{
|
||||
@@ -104,9 +107,6 @@ namespace winrt::TerminalApp::implementation
|
||||
TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable);
|
||||
|
||||
private:
|
||||
static constexpr double HeaderRenameBoxWidthDefault{ 165 };
|
||||
static constexpr double HeaderRenameBoxWidthTitleLength{ std::numeric_limits<double>::infinity() };
|
||||
|
||||
std::shared_ptr<Pane> _rootPane{ nullptr };
|
||||
std::shared_ptr<Pane> _activePane{ nullptr };
|
||||
std::shared_ptr<Pane> _zoomedPane{ nullptr };
|
||||
|
||||
4
src/cascadia/TerminalApp/packages.config
Normal file
4
src/cascadia/TerminalApp/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3-prerelease.220816001" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -41,7 +41,7 @@
|
||||
<!-- Dependencies -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalConnection\TerminalConnection.vcxproj">
|
||||
<Project>{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}</Project>
|
||||
<Project>{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpprest/json.h"
|
||||
|
||||
namespace Microsoft::Terminal::Azure
|
||||
{
|
||||
class AzureException : public std::runtime_error
|
||||
@@ -10,24 +12,14 @@ namespace Microsoft::Terminal::Azure
|
||||
std::wstring _code;
|
||||
|
||||
public:
|
||||
static bool IsErrorPayload(const winrt::Windows::Data::Json::JsonObject& errorObject)
|
||||
static bool IsErrorPayload(const web::json::value& errorObject)
|
||||
{
|
||||
if (!errorObject.HasKey(L"error"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (errorObject.GetNamedValue(L"error").ValueType() != winrt::Windows::Data::Json::JsonValueType::String)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return errorObject.has_string_field(L"error");
|
||||
}
|
||||
|
||||
AzureException(const winrt::Windows::Data::Json::JsonObject& errorObject) :
|
||||
runtime_error(til::u16u8(errorObject.GetNamedString(L"error_description"))), // surface the human-readable description as .what()
|
||||
_code(errorObject.GetNamedString(L"error"))
|
||||
AzureException(const web::json::value& errorObject) :
|
||||
runtime_error(til::u16u8(errorObject.at(L"error_description").as_string())), // surface the human-readable description as .what()
|
||||
_code(errorObject.at(L"error").as_string())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
inline constexpr std::wstring_view AzureClientID = L"0";
|
||||
static constexpr std::wstring_view AzureClientID = L"0";
|
||||
|
||||
@@ -15,24 +15,22 @@
|
||||
#include "winrt/Windows.System.UserProfile.h"
|
||||
#include "../../types/inc/Utils.hpp"
|
||||
|
||||
#include "winrt/Windows.Web.Http.Filters.h"
|
||||
|
||||
using namespace ::Microsoft::Console;
|
||||
using namespace ::Microsoft::Terminal::Azure;
|
||||
|
||||
using namespace web;
|
||||
using namespace web::http;
|
||||
using namespace web::http::client;
|
||||
using namespace web::websockets::client;
|
||||
using namespace winrt::Windows::Security::Credentials;
|
||||
|
||||
static constexpr int CurrentCredentialVersion = 2;
|
||||
static constexpr std::wstring_view PasswordVaultResourceName = L"Terminal";
|
||||
static constexpr std::wstring_view HttpUserAgent = L"Mozilla/5.0 (Windows NT 10.0) Terminal/1.0";
|
||||
static constexpr int CurrentCredentialVersion = 1;
|
||||
static constexpr auto PasswordVaultResourceName = L"Terminal";
|
||||
static constexpr auto HttpUserAgent = L"Terminal/0.0";
|
||||
|
||||
static constexpr int USER_INPUT_COLOR = 93; // yellow - the color of something the user can type
|
||||
static constexpr int USER_INFO_COLOR = 97; // white - the color of clarifying information
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
namespace WDJ = ::winrt::Windows::Data::Json;
|
||||
namespace WSS = ::winrt::Windows::Storage::Streams;
|
||||
namespace WWH = ::winrt::Windows::Web::Http;
|
||||
|
||||
static constexpr winrt::guid AzureConnectionType = { 0xd9fcfdfa, 0xa479, 0x412c, { 0x83, 0xb7, 0xc5, 0x64, 0xe, 0x61, 0xcd, 0x62 } };
|
||||
|
||||
static inline std::wstring _colorize(const unsigned int colorCode, const std::wstring_view text)
|
||||
@@ -117,8 +115,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - creates the output thread (where we will do the authentication and actually connect to Azure)
|
||||
void AzureConnection::Start()
|
||||
{
|
||||
_httpClient = winrt::Windows::Web::Http::HttpClient{};
|
||||
_httpClient.DefaultRequestHeaders().UserAgent().TryParseAdd(HttpUserAgent);
|
||||
// Create our own output handling thread
|
||||
// Each connection needs to make sure to drain the output from its backing host.
|
||||
_hOutputThread.reset(CreateThread(
|
||||
@@ -130,7 +126,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
{
|
||||
return pInstance->_OutputThread();
|
||||
}
|
||||
return gsl::narrow<DWORD>(E_INVALIDARG);
|
||||
return gsl::narrow_cast<DWORD>(E_INVALIDARG);
|
||||
},
|
||||
this,
|
||||
0,
|
||||
@@ -187,8 +183,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
if (_state == AzureState::TermConnected)
|
||||
{
|
||||
auto buff{ winrt::to_string(data) };
|
||||
WinHttpWebSocketSend(_webSocket.get(), WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, buff.data(), gsl::narrow<DWORD>(buff.size()));
|
||||
// If we're connected, we don't need to do any fun input shenanigans.
|
||||
websocket_outgoing_message msg;
|
||||
const auto str = winrt::to_string(data);
|
||||
msg.set_utf8_message(str);
|
||||
|
||||
_cloudShellSocket.send(msg).get();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -238,17 +238,16 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
else // We only transition to Connected when we've established the websocket.
|
||||
{
|
||||
auto uri{ fmt::format(L"{}terminals/{}/size?cols={}&rows={}&version=2019-01-01", _cloudShellUri, _terminalID, columns, rows) };
|
||||
// Initialize client
|
||||
http_client terminalClient(_cloudShellUri);
|
||||
|
||||
WWH::HttpStringContent content{
|
||||
L"",
|
||||
WSS::UnicodeEncoding::Utf8,
|
||||
// LOAD-BEARING. the API returns "'content-type' should be 'application/json' or 'multipart/form-data'"
|
||||
L"application/json"
|
||||
};
|
||||
// Initialize the request
|
||||
http_request terminalRequest(L"POST");
|
||||
terminalRequest.set_request_uri(fmt::format(L"terminals/{}/size?cols={}&rows={}&version=2019-01-01", _terminalID, columns, rows));
|
||||
terminalRequest.set_body(json::value::null());
|
||||
|
||||
// Send the request (don't care about the response)
|
||||
std::ignore = _SendRequestReturningJson(uri, content);
|
||||
(void)_SendAuthenticatedRequestReturningJson(terminalClient, terminalRequest);
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
@@ -265,10 +264,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
if (_state == AzureState::TermConnected)
|
||||
{
|
||||
// Close the websocket connection
|
||||
std::ignore = WinHttpWebSocketClose(_webSocket.get(), WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, nullptr, 0); // throw away the error
|
||||
_webSocket.reset();
|
||||
_socketConnectionHandle.reset();
|
||||
_socketSessionHandle.reset();
|
||||
_cloudShellSocket.close();
|
||||
}
|
||||
|
||||
if (_hOutputThread)
|
||||
@@ -291,46 +287,44 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - tenant - the unparsed tenant
|
||||
// Return value:
|
||||
// - a tuple containing the ID and display name of the tenant.
|
||||
static Tenant _crackTenant(const WDJ::IJsonValue& value)
|
||||
static Tenant _crackTenant(const json::value& jsonTenant)
|
||||
{
|
||||
auto jsonTenant{ value.GetObjectW() };
|
||||
|
||||
Tenant tenant{};
|
||||
if (jsonTenant.HasKey(L"tenantID"))
|
||||
if (jsonTenant.has_string_field(L"tenantID"))
|
||||
{
|
||||
// for compatibility with version 1 credentials
|
||||
tenant.ID = jsonTenant.GetNamedString(L"tenantID");
|
||||
tenant.ID = jsonTenant.at(L"tenantID").as_string();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This one comes in off the wire
|
||||
tenant.ID = jsonTenant.GetNamedString(L"tenantId");
|
||||
tenant.ID = jsonTenant.at(L"tenantId").as_string();
|
||||
}
|
||||
|
||||
if (jsonTenant.HasKey(L"displayName"))
|
||||
if (jsonTenant.has_string_field(L"displayName"))
|
||||
{
|
||||
tenant.DisplayName = jsonTenant.GetNamedString(L"displayName");
|
||||
tenant.DisplayName = jsonTenant.at(L"displayName").as_string();
|
||||
}
|
||||
|
||||
if (jsonTenant.HasKey(L"defaultDomain"))
|
||||
if (jsonTenant.has_string_field(L"defaultDomain"))
|
||||
{
|
||||
tenant.DefaultDomain = jsonTenant.GetNamedString(L"defaultDomain");
|
||||
tenant.DefaultDomain = jsonTenant.at(L"defaultDomain").as_string();
|
||||
}
|
||||
|
||||
return tenant;
|
||||
}
|
||||
|
||||
static void _packTenant(const WDJ::JsonObject& jsonTenant, const Tenant& tenant)
|
||||
static void _packTenant(json::value& jsonTenant, const Tenant& tenant)
|
||||
{
|
||||
jsonTenant.SetNamedValue(L"tenantId", WDJ::JsonValue::CreateStringValue(tenant.ID));
|
||||
jsonTenant[L"tenantId"] = json::value::string(tenant.ID);
|
||||
if (tenant.DisplayName.has_value())
|
||||
{
|
||||
jsonTenant.SetNamedValue(L"displayName", WDJ::JsonValue::CreateStringValue(*tenant.DisplayName));
|
||||
jsonTenant[L"displayName"] = json::value::string(*tenant.DisplayName);
|
||||
}
|
||||
|
||||
if (tenant.DefaultDomain.has_value())
|
||||
{
|
||||
jsonTenant.SetNamedValue(L"defaultDomain", WDJ::JsonValue::CreateStringValue(*tenant.DefaultDomain));
|
||||
jsonTenant[L"defaultDomain"] = json::value::string(*tenant.DefaultDomain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,42 +383,35 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
case AzureState::TermConnected:
|
||||
{
|
||||
_transitionToState(ConnectionState::Connected);
|
||||
|
||||
while (true)
|
||||
{
|
||||
WINHTTP_WEB_SOCKET_BUFFER_TYPE bufferType{};
|
||||
DWORD read{};
|
||||
THROW_IF_WIN32_ERROR(WinHttpWebSocketReceive(_webSocket.get(), _buffer.data(), gsl::narrow<DWORD>(_buffer.size()), &read, &bufferType));
|
||||
|
||||
switch (bufferType)
|
||||
// Read from websocket
|
||||
pplx::task<websocket_incoming_message> msgT;
|
||||
try
|
||||
{
|
||||
case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
|
||||
case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
|
||||
{
|
||||
const auto result{ til::u8u16(std::string_view{ _buffer.data(), read }, _u16Str, _u8State) };
|
||||
if (FAILED(result))
|
||||
{
|
||||
// EXIT POINT
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
return gsl::narrow<DWORD>(result);
|
||||
}
|
||||
|
||||
if (_u16Str.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Pass the output to our registered event handlers
|
||||
_TerminalOutputHandlers(_u16Str);
|
||||
break;
|
||||
msgT = _cloudShellSocket.receive();
|
||||
msgT.wait();
|
||||
}
|
||||
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
|
||||
// EXIT POINT
|
||||
catch (...)
|
||||
{
|
||||
// Websocket has been closed; consider it a graceful exit?
|
||||
// This should result in our termination.
|
||||
if (_transitionToState(ConnectionState::Closed))
|
||||
{
|
||||
// End the output thread.
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
auto msg = msgT.get();
|
||||
auto msgStringTask = msg.extract_string();
|
||||
auto msgString = msgStringTask.get();
|
||||
|
||||
// Convert to hstring
|
||||
const auto hstr = winrt::to_hstring(msgString);
|
||||
|
||||
// Pass the output to our registered event handlers
|
||||
_TerminalOutputHandlers(hstr);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -462,29 +449,25 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
_tenantList.clear();
|
||||
for (const auto& entry : credList)
|
||||
{
|
||||
try
|
||||
auto nameJson = json::value::parse(entry.UserName().c_str());
|
||||
std::optional<int> credentialVersion;
|
||||
if (nameJson.has_integer_field(U("ver")))
|
||||
{
|
||||
auto nameJson = WDJ::JsonObject::Parse(entry.UserName());
|
||||
std::optional<int> credentialVersion;
|
||||
if (nameJson.HasKey(L"ver"))
|
||||
{
|
||||
credentialVersion = static_cast<int>(nameJson.GetNamedNumber(L"ver"));
|
||||
}
|
||||
|
||||
if (!credentialVersion.has_value() || credentialVersion.value() != CurrentCredentialVersion)
|
||||
{
|
||||
// ignore credentials that aren't from the latest credential revision
|
||||
vault.Remove(entry);
|
||||
oldVersionEncountered = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto newTenant{ _tenantList.emplace_back(_crackTenant(nameJson)) };
|
||||
|
||||
_WriteStringWithNewline(_formatTenant(numTenants, newTenant));
|
||||
numTenants++;
|
||||
credentialVersion = nameJson.at(U("ver")).as_integer();
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
if (!credentialVersion.has_value() || credentialVersion.value() != CurrentCredentialVersion)
|
||||
{
|
||||
// ignore credentials that aren't from the latest credential revision
|
||||
vault.Remove(entry);
|
||||
oldVersionEncountered = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto newTenant{ _tenantList.emplace_back(_crackTenant(nameJson)) };
|
||||
|
||||
_WriteStringWithNewline(_formatTenant(numTenants, newTenant));
|
||||
numTenants++;
|
||||
}
|
||||
|
||||
if (!numTenants)
|
||||
@@ -550,11 +533,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// User wants to login with one of the saved connection settings
|
||||
auto desiredCredential = credList.GetAt(selectedTenant);
|
||||
desiredCredential.RetrievePassword();
|
||||
auto passWordJson = WDJ::JsonObject::Parse(desiredCredential.Password());
|
||||
auto passWordJson = json::value::parse(desiredCredential.Password().c_str());
|
||||
_currentTenant = til::at(_tenantList, selectedTenant); // we already unpacked the name info, so we should just use it
|
||||
_setAccessToken(passWordJson.GetNamedString(L"accessToken"));
|
||||
_refreshToken = passWordJson.GetNamedString(L"refreshToken");
|
||||
_expiry = std::stoi(winrt::to_string(passWordJson.GetNamedString(L"expiry")));
|
||||
_accessToken = passWordJson.at(L"accessToken").as_string();
|
||||
_refreshToken = passWordJson.at(L"refreshToken").as_string();
|
||||
_expiry = std::stoi(passWordJson.at(L"expiry").as_string());
|
||||
|
||||
const auto t1 = std::chrono::system_clock::now();
|
||||
const auto timeNow = std::chrono::duration_cast<std::chrono::seconds>(t1.time_since_epoch()).count();
|
||||
@@ -594,17 +577,17 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const auto deviceCodeResponse = _GetDeviceCode();
|
||||
|
||||
// Print the message and store the device code, polling interval and expiry
|
||||
const auto message{ deviceCodeResponse.GetNamedString(L"message") };
|
||||
const auto message = winrt::to_hstring(deviceCodeResponse.at(L"message").as_string().c_str());
|
||||
_WriteStringWithNewline(message);
|
||||
_WriteStringWithNewline(RS_(L"AzureCodeExpiry"));
|
||||
const auto devCode = deviceCodeResponse.GetNamedString(L"device_code");
|
||||
const auto pollInterval = std::stoi(winrt::to_string(deviceCodeResponse.GetNamedString(L"interval")));
|
||||
const auto expiresIn = std::stoi(winrt::to_string(deviceCodeResponse.GetNamedString(L"expires_in")));
|
||||
const auto devCode = deviceCodeResponse.at(L"device_code").as_string();
|
||||
const auto pollInterval = std::stoi(deviceCodeResponse.at(L"interval").as_string());
|
||||
const auto expiresIn = std::stoi(deviceCodeResponse.at(L"expires_in").as_string());
|
||||
|
||||
// Wait for user authentication and obtain the access/refresh tokens
|
||||
auto authenticatedResponse = _WaitForUser(devCode, pollInterval, expiresIn);
|
||||
_setAccessToken(authenticatedResponse.GetNamedString(L"access_token"));
|
||||
_refreshToken = authenticatedResponse.GetNamedString(L"refresh_token");
|
||||
_accessToken = authenticatedResponse.at(L"access_token").as_string();
|
||||
_refreshToken = authenticatedResponse.at(L"refresh_token").as_string();
|
||||
|
||||
// Get the tenants and the required tenant id
|
||||
_PopulateTenantList();
|
||||
@@ -713,18 +696,19 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - Helper function to parse the preferred shell type from user settings returned by cloud console API.
|
||||
// We need this function because the field might be missing in the settings
|
||||
// created with old versions of cloud console API.
|
||||
winrt::hstring AzureConnection::_ParsePreferredShellType(const WDJ::JsonObject& settingsResponse)
|
||||
std::optional<utility::string_t> AzureConnection::_ParsePreferredShellType(const web::json::value& settingsResponse)
|
||||
{
|
||||
if (settingsResponse.HasKey(L"properties"))
|
||||
if (settingsResponse.has_object_field(L"properties"))
|
||||
{
|
||||
const auto userSettings = settingsResponse.GetNamedObject(L"properties");
|
||||
if (userSettings.HasKey(L"preferredShellType"))
|
||||
const auto userSettings = settingsResponse.at(L"properties");
|
||||
if (userSettings.has_string_field(L"preferredShellType"))
|
||||
{
|
||||
return userSettings.GetNamedString(L"preferredShellType");
|
||||
const auto preferredShellTypeValue = userSettings.at(L"preferredShellType");
|
||||
return preferredShellTypeValue.as_string();
|
||||
}
|
||||
}
|
||||
|
||||
return L"pwsh";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
@@ -733,7 +717,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
{
|
||||
// Get user's cloud shell settings
|
||||
const auto settingsResponse = _GetCloudShellUserSettings();
|
||||
if (settingsResponse.HasKey(L"error"))
|
||||
if (settingsResponse.has_field(L"error"))
|
||||
{
|
||||
_WriteStringWithNewline(RS_(L"AzureNoCloudAccount"));
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
@@ -748,36 +732,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// Request for a terminal for said cloud shell
|
||||
const auto shellType = _ParsePreferredShellType(settingsResponse);
|
||||
_WriteStringWithNewline(RS_(L"AzureRequestingTerminal"));
|
||||
const auto socketUri = _GetTerminal(shellType);
|
||||
const auto socketUri = _GetTerminal(shellType.value_or(L"pwsh"));
|
||||
_TerminalOutputHandlers(L"\r\n");
|
||||
|
||||
//// Step 8: connecting to said terminal
|
||||
{
|
||||
wil::unique_winhttp_hinternet sessionHandle, connectionHandle, requestHandle, socketHandle;
|
||||
Uri parsedUri{ socketUri };
|
||||
sessionHandle.reset(WinHttpOpen(HttpUserAgent.data(), WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, nullptr, nullptr, 0));
|
||||
THROW_LAST_ERROR_IF(!sessionHandle);
|
||||
|
||||
connectionHandle.reset(WinHttpConnect(sessionHandle.get(), parsedUri.Host().c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0));
|
||||
THROW_LAST_ERROR_IF(!connectionHandle);
|
||||
|
||||
requestHandle.reset(WinHttpOpenRequest(connectionHandle.get(), L"GET", parsedUri.Path().c_str(), nullptr, nullptr, nullptr, WINHTTP_FLAG_SECURE));
|
||||
THROW_LAST_ERROR_IF(!requestHandle);
|
||||
|
||||
THROW_IF_WIN32_BOOL_FALSE(WinHttpSetOption(requestHandle.get(), WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, nullptr, 0));
|
||||
#pragma warning(suppress : 26477) // WINHTTP_NO_ADDITIONAL_HEADERS expands to NULL rather than nullptr (who would have thought?)
|
||||
THROW_IF_WIN32_BOOL_FALSE(WinHttpSendRequest(requestHandle.get(), WINHTTP_NO_ADDITIONAL_HEADERS, 0, nullptr, 0, 0, 0));
|
||||
THROW_IF_WIN32_BOOL_FALSE(WinHttpReceiveResponse(requestHandle.get(), nullptr));
|
||||
|
||||
socketHandle.reset(WinHttpWebSocketCompleteUpgrade(requestHandle.get(), 0));
|
||||
THROW_LAST_ERROR_IF(!socketHandle);
|
||||
|
||||
requestHandle.reset(); // We no longer need the request once we've upgraded it.
|
||||
// We have to keep the socket session and connection handles.
|
||||
_socketSessionHandle = std::move(sessionHandle);
|
||||
_socketConnectionHandle = std::move(connectionHandle);
|
||||
_webSocket = std::move(socketHandle);
|
||||
}
|
||||
// Step 8: connecting to said terminal
|
||||
const auto connReqTask = _cloudShellSocket.connect(socketUri);
|
||||
connReqTask.wait();
|
||||
|
||||
_state = AzureState::TermConnected;
|
||||
|
||||
@@ -792,52 +752,58 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// Method description:
|
||||
// - helper function to send requests with default headers and extract responses as json values
|
||||
// Arguments:
|
||||
// - the URI
|
||||
// - optional body content
|
||||
// - an optional HTTP method (defaults to POST if content is present, GET otherwise)
|
||||
// - a http_client
|
||||
// - a http_request for the client to send
|
||||
// Return value:
|
||||
// - the response from the server as a json value
|
||||
WDJ::JsonObject AzureConnection::_SendRequestReturningJson(std::wstring_view uri, const WWH::IHttpContent& content, WWH::HttpMethod method)
|
||||
json::value AzureConnection::_SendRequestReturningJson(http_client& theClient, http_request theRequest)
|
||||
{
|
||||
if (!method)
|
||||
{
|
||||
method = content == nullptr ? WWH::HttpMethod::Get() : WWH::HttpMethod::Post();
|
||||
}
|
||||
auto& headers{ theRequest.headers() };
|
||||
headers.add(L"User-Agent", HttpUserAgent);
|
||||
headers.add(L"Accept", L"application/json");
|
||||
|
||||
WWH::HttpRequestMessage request{ method, Uri{ uri } };
|
||||
request.Content(content);
|
||||
|
||||
auto headers{ request.Headers() };
|
||||
headers.Accept().TryParseAdd(L"application/json");
|
||||
|
||||
const auto response{ _httpClient.SendRequestAsync(request).get() };
|
||||
const auto string{ response.Content().ReadAsStringAsync().get() };
|
||||
const auto jsonResult{ WDJ::JsonObject::Parse(string) };
|
||||
json::value jsonResult;
|
||||
const auto responseTask = theClient.request(theRequest);
|
||||
responseTask.wait();
|
||||
const auto response = responseTask.get();
|
||||
const auto responseJsonTask = response.extract_json();
|
||||
responseJsonTask.wait();
|
||||
jsonResult = responseJsonTask.get();
|
||||
|
||||
THROW_IF_AZURE_ERROR(jsonResult);
|
||||
return jsonResult;
|
||||
}
|
||||
|
||||
void AzureConnection::_setAccessToken(std::wstring_view accessToken)
|
||||
// Method description:
|
||||
// - helper function to send _authenticated_ requests with json bodies whose responses are expected
|
||||
// to be json. builds on _SendRequestReturningJson.
|
||||
// Arguments:
|
||||
// - the http_request
|
||||
json::value AzureConnection::_SendAuthenticatedRequestReturningJson(http_client& theClient, http_request theRequest)
|
||||
{
|
||||
_accessToken = accessToken;
|
||||
_httpClient.DefaultRequestHeaders().Authorization(WWH::Headers::HttpCredentialsHeaderValue{ L"Bearer", _accessToken });
|
||||
auto& headers{ theRequest.headers() };
|
||||
headers.add(L"Authorization", L"Bearer " + _accessToken);
|
||||
|
||||
return _SendRequestReturningJson(theClient, std::move(theRequest));
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to start the device code flow
|
||||
// Return value:
|
||||
// - the response to the device code flow initiation
|
||||
WDJ::JsonObject AzureConnection::_GetDeviceCode()
|
||||
json::value AzureConnection::_GetDeviceCode()
|
||||
{
|
||||
auto uri{ fmt::format(L"{}common/oauth2/devicecode", _loginUri) };
|
||||
WWH::HttpFormUrlEncodedContent content{
|
||||
std::unordered_map<winrt::hstring, winrt::hstring>{
|
||||
{ winrt::hstring{ L"client_id" }, winrt::hstring{ AzureClientID } },
|
||||
{ winrt::hstring{ L"resource" }, winrt::hstring{ _wantedResource } },
|
||||
}
|
||||
};
|
||||
return _SendRequestReturningJson(uri, content);
|
||||
// Initialize the client
|
||||
http_client loginClient(_loginUri);
|
||||
|
||||
// Initialize the request
|
||||
http_request commonRequest(L"POST");
|
||||
commonRequest.set_request_uri(L"common/oauth2/devicecode");
|
||||
const auto body{ fmt::format(L"client_id={}&resource={}", AzureClientID, _wantedResource) };
|
||||
commonRequest.set_body(body.c_str(), L"application/x-www-form-urlencoded");
|
||||
|
||||
// Send the request and receive the response as a json value
|
||||
return _SendRequestReturningJson(loginClient, commonRequest);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
@@ -849,17 +815,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// Return value:
|
||||
// - if authentication is done successfully, then return the response from the server
|
||||
// - else, throw an exception
|
||||
WDJ::JsonObject AzureConnection::_WaitForUser(const winrt::hstring& deviceCode, int pollInterval, int expiresIn)
|
||||
json::value AzureConnection::_WaitForUser(const utility::string_t deviceCode, int pollInterval, int expiresIn)
|
||||
{
|
||||
auto uri{ fmt::format(L"{}common/oauth2/token", _loginUri) };
|
||||
WWH::HttpFormUrlEncodedContent content{
|
||||
std::unordered_map<winrt::hstring, winrt::hstring>{
|
||||
{ winrt::hstring{ L"grant_type" }, winrt::hstring{ L"device_code" } },
|
||||
{ winrt::hstring{ L"client_id" }, winrt::hstring{ AzureClientID } },
|
||||
{ winrt::hstring{ L"resource" }, winrt::hstring{ _wantedResource } },
|
||||
{ winrt::hstring{ L"code" }, deviceCode },
|
||||
}
|
||||
};
|
||||
// Initialize the client
|
||||
http_client pollingClient(_loginUri);
|
||||
|
||||
// Continuously send a poll request until the user authenticates
|
||||
const auto body{ fmt::format(L"grant_type=device_code&resource={}&client_id={}&code={}", _wantedResource, AzureClientID, deviceCode) };
|
||||
const auto requestUri = L"common/oauth2/token";
|
||||
|
||||
// use a steady clock here so it's not impacted by local time discontinuities
|
||||
const auto tokenExpiry{ std::chrono::steady_clock::now() + std::chrono::seconds(expiresIn) };
|
||||
@@ -874,11 +837,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
break;
|
||||
}
|
||||
|
||||
http_request pollRequest(L"POST");
|
||||
pollRequest.set_request_uri(requestUri);
|
||||
pollRequest.set_body(body.c_str(), L"application/x-www-form-urlencoded");
|
||||
|
||||
try
|
||||
{
|
||||
auto response = _SendRequestReturningJson(uri, content);
|
||||
auto response{ _SendRequestReturningJson(pollingClient, pollRequest) };
|
||||
_WriteStringWithNewline(RS_(L"AzureSuccessfullyAuthenticated"));
|
||||
|
||||
// Got a valid response: we're done
|
||||
return response;
|
||||
}
|
||||
@@ -893,7 +859,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
} // uncaught exceptions bubble up to the caller
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return json::value::null();
|
||||
}
|
||||
|
||||
// Method description:
|
||||
@@ -902,11 +868,16 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - the response which contains a list of the user's Azure tenants
|
||||
void AzureConnection::_PopulateTenantList()
|
||||
{
|
||||
auto uri{ fmt::format(L"{}tenants?api-version=2020-01-01", _resourceUri) };
|
||||
// Initialize the client
|
||||
http_client tenantClient(_resourceUri);
|
||||
|
||||
// Initialize the request
|
||||
http_request tenantRequest(L"GET");
|
||||
tenantRequest.set_request_uri(L"tenants?api-version=2020-01-01");
|
||||
|
||||
// Send the request and return the response as a json value
|
||||
auto tenantResponse{ _SendRequestReturningJson(uri, nullptr) };
|
||||
auto tenantList{ tenantResponse.GetNamedArray(L"value") };
|
||||
auto tenantResponse{ _SendAuthenticatedRequestReturningJson(tenantClient, tenantRequest) };
|
||||
auto tenantList{ tenantResponse.at(L"value").as_array() };
|
||||
|
||||
_tenantList.clear();
|
||||
std::transform(tenantList.begin(), tenantList.end(), std::back_inserter(_tenantList), _crackTenant);
|
||||
@@ -918,73 +889,82 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - the response with the new tokens
|
||||
void AzureConnection::_RefreshTokens()
|
||||
{
|
||||
auto uri{ fmt::format(L"{}{}/oauth2/token", _loginUri, _currentTenant->ID) };
|
||||
WWH::HttpFormUrlEncodedContent content{
|
||||
std::unordered_map<winrt::hstring, winrt::hstring>{
|
||||
{ winrt::hstring{ L"grant_type" }, winrt::hstring{ L"refresh_token" } },
|
||||
{ winrt::hstring{ L"client_id" }, winrt::hstring{ AzureClientID } },
|
||||
{ winrt::hstring{ L"resource" }, winrt::hstring{ _wantedResource } },
|
||||
{ winrt::hstring{ L"refresh_token" }, winrt::hstring{ _refreshToken } },
|
||||
}
|
||||
};
|
||||
// Initialize the client
|
||||
http_client refreshClient(_loginUri);
|
||||
|
||||
// Initialize the request
|
||||
http_request refreshRequest(L"POST");
|
||||
refreshRequest.set_request_uri(_currentTenant->ID + L"/oauth2/token");
|
||||
const auto body{ fmt::format(L"client_id={}&resource={}&grant_type=refresh_token&refresh_token={}", AzureClientID, _wantedResource, _refreshToken) };
|
||||
refreshRequest.set_body(body.c_str(), L"application/x-www-form-urlencoded");
|
||||
|
||||
// Send the request and return the response as a json value
|
||||
auto refreshResponse{ _SendRequestReturningJson(uri, content) };
|
||||
_setAccessToken(refreshResponse.GetNamedString(L"access_token"));
|
||||
_refreshToken = refreshResponse.GetNamedString(L"refresh_token");
|
||||
_expiry = std::stoi(winrt::to_string(refreshResponse.GetNamedString(L"expires_on")));
|
||||
auto refreshResponse{ _SendRequestReturningJson(refreshClient, refreshRequest) };
|
||||
_accessToken = refreshResponse.at(L"access_token").as_string();
|
||||
_refreshToken = refreshResponse.at(L"refresh_token").as_string();
|
||||
_expiry = std::stoi(refreshResponse.at(L"expires_on").as_string());
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to get the user's cloud shell settings
|
||||
// Return value:
|
||||
// - the user's cloud shell settings
|
||||
WDJ::JsonObject AzureConnection::_GetCloudShellUserSettings()
|
||||
json::value AzureConnection::_GetCloudShellUserSettings()
|
||||
{
|
||||
auto uri{ fmt::format(L"{}providers/Microsoft.Portal/userSettings/cloudconsole?api-version=2020-04-01-preview", _resourceUri) };
|
||||
return _SendRequestReturningJson(uri, nullptr);
|
||||
// Initialize client
|
||||
http_client settingsClient(_resourceUri);
|
||||
|
||||
// Initialize request
|
||||
http_request settingsRequest(L"GET");
|
||||
settingsRequest.set_request_uri(L"providers/Microsoft.Portal/userSettings/cloudconsole?api-version=2018-10-01");
|
||||
|
||||
return _SendAuthenticatedRequestReturningJson(settingsClient, settingsRequest);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to request for a cloud shell
|
||||
// Return value:
|
||||
// - the uri for the cloud shell
|
||||
winrt::hstring AzureConnection::_GetCloudShell()
|
||||
utility::string_t AzureConnection::_GetCloudShell()
|
||||
{
|
||||
auto uri{ fmt::format(L"{}providers/Microsoft.Portal/consoles/default?api-version=2020-04-01-preview", _resourceUri) };
|
||||
// Initialize client
|
||||
http_client cloudShellClient(_resourceUri);
|
||||
|
||||
WWH::HttpStringContent content{
|
||||
LR"-({"properties": {"osType": "linux"}})-",
|
||||
WSS::UnicodeEncoding::Utf8,
|
||||
L"application/json"
|
||||
};
|
||||
// Initialize request
|
||||
http_request shellRequest(L"PUT");
|
||||
shellRequest.set_request_uri(L"providers/Microsoft.Portal/consoles/default?api-version=2018-10-01");
|
||||
// { "properties": { "osType": "linux" } }
|
||||
auto body = json::value::object({ { U("properties"), json::value::object({ { U("osType"), json::value::string(U("linux")) } }) } });
|
||||
shellRequest.set_body(body);
|
||||
|
||||
const auto cloudShell = _SendRequestReturningJson(uri, content, WWH::HttpMethod::Put());
|
||||
// Send the request and get the response as a json value
|
||||
const auto cloudShell = _SendAuthenticatedRequestReturningJson(cloudShellClient, shellRequest);
|
||||
|
||||
// Return the uri
|
||||
return winrt::hstring{ std::wstring{ cloudShell.GetNamedObject(L"properties").GetNamedString(L"uri") } + L"/" };
|
||||
return cloudShell.at(L"properties").at(L"uri").as_string() + L"/";
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to request for a terminal
|
||||
// Return value:
|
||||
// - the uri for the terminal
|
||||
winrt::hstring AzureConnection::_GetTerminal(const winrt::hstring& shellType)
|
||||
utility::string_t AzureConnection::_GetTerminal(utility::string_t shellType)
|
||||
{
|
||||
auto uri{ fmt::format(L"{}terminals?cols={}&rows={}&version=2019-01-01&shell={}", _cloudShellUri, _initialCols, _initialRows, shellType) };
|
||||
// Initialize client
|
||||
http_client terminalClient(_cloudShellUri);
|
||||
|
||||
WWH::HttpStringContent content{
|
||||
L"",
|
||||
WSS::UnicodeEncoding::Utf8,
|
||||
// LOAD-BEARING. the API returns "'content-type' should be 'application/json' or 'multipart/form-data'"
|
||||
L"application/json"
|
||||
};
|
||||
// Initialize the request
|
||||
http_request terminalRequest(L"POST");
|
||||
terminalRequest.set_request_uri(fmt::format(L"terminals?cols={}&rows={}&version=2019-01-01&shell={}", _initialCols, _initialRows, shellType));
|
||||
// LOAD-BEARING. the API returns "'content-type' should be 'application/json' or 'multipart/form-data'"
|
||||
terminalRequest.set_body(json::value::null());
|
||||
|
||||
const auto terminalResponse = _SendRequestReturningJson(uri, content);
|
||||
_terminalID = terminalResponse.GetNamedString(L"id");
|
||||
// Send the request and get the response as a json value
|
||||
const auto terminalResponse = _SendAuthenticatedRequestReturningJson(terminalClient, terminalRequest);
|
||||
_terminalID = terminalResponse.at(L"id").as_string();
|
||||
|
||||
// Return the uri
|
||||
return terminalResponse.GetNamedString(L"socketUri");
|
||||
return terminalResponse.at(L"socketUri").as_string();
|
||||
}
|
||||
|
||||
// Method description:
|
||||
@@ -992,17 +972,16 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - we store the display name, tenant ID, access/refresh tokens, and token expiry
|
||||
void AzureConnection::_StoreCredential()
|
||||
{
|
||||
WDJ::JsonObject userName;
|
||||
userName.SetNamedValue(L"ver", WDJ::JsonValue::CreateNumberValue(CurrentCredentialVersion));
|
||||
json::value userName;
|
||||
userName[U("ver")] = CurrentCredentialVersion;
|
||||
_packTenant(userName, *_currentTenant);
|
||||
|
||||
WDJ::JsonObject passWord;
|
||||
passWord.SetNamedValue(L"accessToken", WDJ::JsonValue::CreateStringValue(_accessToken));
|
||||
passWord.SetNamedValue(L"refreshToken", WDJ::JsonValue::CreateStringValue(_refreshToken));
|
||||
passWord.SetNamedValue(L"expiry", WDJ::JsonValue::CreateStringValue(std::to_wstring(_expiry)));
|
||||
json::value passWord;
|
||||
passWord[U("accessToken")] = json::value::string(_accessToken);
|
||||
passWord[U("refreshToken")] = json::value::string(_refreshToken);
|
||||
passWord[U("expiry")] = json::value::string(std::to_wstring(_expiry));
|
||||
|
||||
PasswordVault vault;
|
||||
PasswordCredential newCredential{ PasswordVaultResourceName, userName.Stringify(), passWord.Stringify() };
|
||||
PasswordCredential newCredential{ PasswordVaultResourceName, userName.serialize(), passWord.serialize() };
|
||||
vault.Add(newCredential);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
#include "AzureConnection.g.h"
|
||||
|
||||
#include <cpprest/http_client.h>
|
||||
#include <cpprest/http_listener.h>
|
||||
#include <cpprest/ws_client.h>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
@@ -53,30 +56,30 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
void _RunStoreState();
|
||||
void _RunConnectState();
|
||||
|
||||
static constexpr std::wstring_view _loginUri{ L"https://login.microsoftonline.com/" };
|
||||
static constexpr std::wstring_view _resourceUri{ L"https://management.azure.com/" };
|
||||
static constexpr std::wstring_view _wantedResource{ L"https://management.core.windows.net/" };
|
||||
const utility::string_t _loginUri{ U("https://login.microsoftonline.com/") };
|
||||
const utility::string_t _resourceUri{ U("https://management.azure.com/") };
|
||||
const utility::string_t _wantedResource{ U("https://management.core.windows.net/") };
|
||||
const int _expireLimit{ 2700 };
|
||||
winrt::hstring _accessToken;
|
||||
winrt::hstring _refreshToken;
|
||||
utility::string_t _accessToken;
|
||||
utility::string_t _refreshToken;
|
||||
int _expiry{ 0 };
|
||||
winrt::hstring _cloudShellUri;
|
||||
winrt::hstring _terminalID;
|
||||
utility::string_t _cloudShellUri;
|
||||
utility::string_t _terminalID;
|
||||
|
||||
std::vector<::Microsoft::Terminal::Azure::Tenant> _tenantList;
|
||||
std::optional<::Microsoft::Terminal::Azure::Tenant> _currentTenant;
|
||||
|
||||
void _WriteStringWithNewline(const std::wstring_view str);
|
||||
void _WriteCaughtExceptionRecord();
|
||||
winrt::Windows::Data::Json::JsonObject _SendRequestReturningJson(std::wstring_view uri, const winrt::Windows::Web::Http::IHttpContent& content = nullptr, winrt::Windows::Web::Http::HttpMethod method = nullptr);
|
||||
void _setAccessToken(std::wstring_view accessToken);
|
||||
winrt::Windows::Data::Json::JsonObject _GetDeviceCode();
|
||||
winrt::Windows::Data::Json::JsonObject _WaitForUser(const winrt::hstring& deviceCode, int pollInterval, int expiresIn);
|
||||
web::json::value _SendRequestReturningJson(web::http::client::http_client& theClient, web::http::http_request theRequest);
|
||||
web::json::value _SendAuthenticatedRequestReturningJson(web::http::client::http_client& theClient, web::http::http_request theRequest);
|
||||
web::json::value _GetDeviceCode();
|
||||
web::json::value _WaitForUser(utility::string_t deviceCode, int pollInterval, int expiresIn);
|
||||
void _PopulateTenantList();
|
||||
void _RefreshTokens();
|
||||
winrt::Windows::Data::Json::JsonObject _GetCloudShellUserSettings();
|
||||
winrt::hstring _GetCloudShell();
|
||||
winrt::hstring _GetTerminal(const winrt::hstring& shellType);
|
||||
web::json::value _GetCloudShellUserSettings();
|
||||
utility::string_t _GetCloudShell();
|
||||
utility::string_t _GetTerminal(utility::string_t shellType);
|
||||
void _StoreCredential();
|
||||
void _RemoveCredentials();
|
||||
|
||||
@@ -92,16 +95,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
std::optional<std::wstring> _ReadUserInput(InputMode mode);
|
||||
|
||||
winrt::Windows::Web::Http::HttpClient _httpClient{ nullptr };
|
||||
wil::unique_winhttp_hinternet _socketSessionHandle;
|
||||
wil::unique_winhttp_hinternet _socketConnectionHandle;
|
||||
wil::unique_winhttp_hinternet _webSocket;
|
||||
web::websockets::client::websocket_client _cloudShellSocket;
|
||||
|
||||
til::u8state _u8State{};
|
||||
std::wstring _u16Str;
|
||||
std::array<char, 4096> _buffer{};
|
||||
|
||||
static winrt::hstring _ParsePreferredShellType(const winrt::Windows::Data::Json::JsonObject& settingsResponse);
|
||||
static std::optional<utility::string_t> _ParsePreferredShellType(const web::json::value& settingsResponse);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalCppRestSDK>true</TerminalCppRestSDK>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -98,4 +99,39 @@
|
||||
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<!--
|
||||
BODGY:
|
||||
|
||||
We depend on `cpprest142*.dll`, which comes from our vcpkg dependency. As a
|
||||
part of the vcpkg dependency restore, msbuild will call the `deployBinary()`
|
||||
function in
|
||||
`packages\vcpkg-cpprestsdk.2.10.14\scripts\BuildSystems\msbuild\AppLocal.ps1`.
|
||||
That function does the actual job of copying the file. It copies it outside of
|
||||
MsBuild. MsBuild then, in the `_CopyFilesMarkedCopyLocal` target, determines
|
||||
that it needs to copy `cpprest142*.dll`, because that dll is a member of
|
||||
`@(ReferencesCopiedInThisBuild)`. However, the file's already been copied, so
|
||||
MsBuild never copies it. But that also prevents MsBuild from setting
|
||||
`WroteAtLeastOneFile`, which then means that MsBuild will never create the
|
||||
.CopyComplete file for this project.
|
||||
|
||||
Because that file is missing, MsBuild will never think the project is up to
|
||||
date, and the FastUpToDate check in VS will always force MsBuild to run a pass
|
||||
on this project.
|
||||
|
||||
To mitigate this, we're adding this other target here, which runs after
|
||||
_CopyFilesMarkedCopyLocal, and always creates the CopyUpToDateMarker. This
|
||||
makes the FastUpToDate check succeed.
|
||||
-->
|
||||
|
||||
<Target
|
||||
Name="_Post_CopyFilesMarkedCopyLocal"
|
||||
AfterTargets="_CopyFilesMarkedCopyLocal"
|
||||
Condition="'@(ReferenceCopyLocalPaths)' != ''">
|
||||
|
||||
<Touch Files="@(CopyUpToDateMarker)"
|
||||
AlwaysCreate="true" />
|
||||
</Target>
|
||||
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -24,14 +24,8 @@
|
||||
|
||||
#include "winrt/Windows.Security.Credentials.h"
|
||||
#include "winrt/Windows.Foundation.Collections.h"
|
||||
#include "winrt/Windows.Web.Http.h"
|
||||
#include "winrt/Windows.Web.Http.Headers.h"
|
||||
#include "winrt/Windows.Data.Json.h"
|
||||
#include <Windows.h>
|
||||
|
||||
#include <winhttp.h>
|
||||
#include <wil/resource.h>
|
||||
|
||||
#include <TraceLoggingProvider.h>
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hTerminalConnectionProvider);
|
||||
#include <telemetry/ProjectTelemetry.h>
|
||||
|
||||
@@ -1100,7 +1100,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// content, which is unexpected.
|
||||
const auto htmlData = formats == nullptr || WI_IsFlagSet(formats.Value(), CopyFormat::HTML) ?
|
||||
TextBuffer::GenHTML(bufferData,
|
||||
_actualFont.GetUnscaledSize().height,
|
||||
_actualFont.GetUnscaledSize().width,
|
||||
_actualFont.GetFaceName(),
|
||||
bgColor) :
|
||||
"";
|
||||
|
||||
@@ -2891,22 +2891,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto lastHoveredCell = _core.HoveredCell();
|
||||
if (lastHoveredCell)
|
||||
{
|
||||
winrt::hstring uriText = _core.HoveredUriText();
|
||||
if (uriText.empty())
|
||||
const auto uriText = _core.HoveredUriText();
|
||||
if (!uriText.empty())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// DisplayUri will filter out non-printable characters and confusables.
|
||||
Windows::Foundation::Uri parsedUri{ uriText };
|
||||
if (!parsedUri)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
uriText = parsedUri.DisplayUri();
|
||||
|
||||
const auto panel = SwapChainPanel();
|
||||
const auto scale = panel.CompositionScaleX();
|
||||
const auto offset = panel.ActualOffset();
|
||||
@@ -2928,7 +2915,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), locationInDIPs.x - offset.x);
|
||||
OverlayCanvas().SetTop(HyperlinkTooltipBorder(), locationInDIPs.y - offset.y);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
-->
|
||||
|
||||
<x:Double x:Key="ScrollBarSize">16</x:Double>
|
||||
<CornerRadius x:Key="ScrollBarCornerRadius">0</CornerRadius>
|
||||
<CornerRadius x:Key="ScrollBarThumbCornerRadius">3</CornerRadius>
|
||||
|
||||
<Style x:Key="ForkedScrollbarTemplate"
|
||||
TargetType="ScrollBar">
|
||||
@@ -118,16 +120,16 @@
|
||||
Value="{ThemeResource ScrollBarButtonArrowForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0.016"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:30"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0.016"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:30"
|
||||
@@ -185,16 +187,16 @@
|
||||
Value="{ThemeResource ScrollBarButtonArrowForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0.016"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:30"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0.016"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:30"
|
||||
@@ -251,16 +253,16 @@
|
||||
Value="{ThemeResource ScrollBarButtonArrowForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0.016"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:30"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0.016"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:30"
|
||||
@@ -317,16 +319,16 @@
|
||||
Value="{ThemeResource ScrollBarButtonArrowForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0.016"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:30"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0.016"
|
||||
Value="{ThemeResource ScrollBarButtonArrowScalePressed}" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:30"
|
||||
@@ -350,11 +352,9 @@
|
||||
<ControlTemplate x:Key="VerticalThumbTemplate"
|
||||
TargetType="Thumb">
|
||||
<Rectangle x:Name="ThumbVisual"
|
||||
contract7NotPresent:RadiusX="{Binding Source={ThemeResource ScrollBarCornerRadius}, Converter={StaticResource TopLeftCornerRadiusDoubleValueConverter}}"
|
||||
contract7NotPresent:RadiusY="{Binding Source={ThemeResource ScrollBarCornerRadius}, Converter={StaticResource BottomRightCornerRadiusDoubleValueConverter}}"
|
||||
contract7Present:RadiusX="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TopLeftCornerRadiusDoubleValueConverter}}"
|
||||
contract7Present:RadiusY="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BottomRightCornerRadiusDoubleValueConverter}}"
|
||||
Fill="{TemplateBinding Background}"
|
||||
RadiusX="{Binding Source={ThemeResource ScrollBarThumbCornerRadius}, Converter={StaticResource TopLeftCornerRadiusDoubleValueConverter}}"
|
||||
RadiusY="{Binding Source={ThemeResource ScrollBarThumbCornerRadius}, Converter={StaticResource BottomRightCornerRadiusDoubleValueConverter}}"
|
||||
Stroke="{TemplateBinding BorderBrush}"
|
||||
StrokeThickness="{ThemeResource ScrollBarThumbStrokeThickness}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
@@ -409,7 +409,6 @@
|
||||
</ControlTemplate>
|
||||
</Grid.Resources>
|
||||
|
||||
<!-- Windows Terminal: This is another addition/customization made by us. -->
|
||||
<VisualStateManager.CustomVisualStateManager>
|
||||
<local:ScrollBarVisualStateManager />
|
||||
</VisualStateManager.CustomVisualStateManager>
|
||||
@@ -426,13 +425,13 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!--
|
||||
Windows Terminal: Here we've removed the corner radius
|
||||
to make our scrollbars be flush with the window frame.
|
||||
-->
|
||||
<Rectangle x:Name="HorizontalTrackRect"
|
||||
Grid.ColumnSpan="5"
|
||||
Margin="0"
|
||||
contract7NotPresent:RadiusX="{Binding Source={ThemeResource ScrollBarCornerRadius}, Converter={StaticResource TopLeftCornerRadiusDoubleValueConverter2x}}"
|
||||
contract7NotPresent:RadiusY="{Binding Source={ThemeResource ScrollBarCornerRadius}, Converter={StaticResource BottomRightCornerRadiusDoubleValueConverter2x}}"
|
||||
contract7Present:RadiusX="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TopLeftCornerRadiusDoubleValueConverter2x}}"
|
||||
contract7Present:RadiusY="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BottomRightCornerRadiusDoubleValueConverter2x}}"
|
||||
Fill="{ThemeResource ScrollBarTrackFill}"
|
||||
Opacity="0"
|
||||
Stroke="{ThemeResource ScrollBarTrackStroke}"
|
||||
@@ -521,13 +520,13 @@
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<!--
|
||||
Windows Terminal: Here we've removed the corner radius
|
||||
to make our scrollbars be flush with the window frame.
|
||||
-->
|
||||
<Rectangle x:Name="VerticalTrackRect"
|
||||
Grid.RowSpan="5"
|
||||
Margin="0"
|
||||
contract7NotPresent:RadiusX="{Binding Source={ThemeResource ScrollBarCornerRadius}, Converter={StaticResource TopLeftCornerRadiusDoubleValueConverter2x}}"
|
||||
contract7NotPresent:RadiusY="{Binding Source={ThemeResource ScrollBarCornerRadius}, Converter={StaticResource BottomRightCornerRadiusDoubleValueConverter2x}}"
|
||||
contract7Present:RadiusX="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TopLeftCornerRadiusDoubleValueConverter2x}}"
|
||||
contract7Present:RadiusY="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BottomRightCornerRadiusDoubleValueConverter2x}}"
|
||||
Fill="{ThemeResource ScrollBarTrackFill}"
|
||||
Opacity="0"
|
||||
Stroke="{ThemeResource ScrollBarTrackStroke}"
|
||||
@@ -930,7 +929,6 @@
|
||||
To="1"
|
||||
Duration="{StaticResource ScrollBarOpacityChangeDuration}" />
|
||||
|
||||
<!-- Because of the blurriness caused by SCALE animation performed on the object with rounded corners, we have to use dependent animation on width to rerasterize the mask on every tick of the animation. -->
|
||||
<DoubleAnimationUsingKeyFrames BeginTime="{StaticResource ScrollBarExpandBeginTime}"
|
||||
EnableDependentAnimation="True"
|
||||
Storyboard.TargetName="VerticalThumb"
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
#include <til/ticket_lock.h>
|
||||
|
||||
inline constexpr std::wstring_view linkPattern{ LR"(\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|$!:,.;]*[A-Za-z0-9+&@#/%=~_|$])" };
|
||||
inline constexpr size_t TaskbarMinProgress{ 10 };
|
||||
static constexpr std::wstring_view linkPattern{ LR"(\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|$!:,.;]*[A-Za-z0-9+&@#/%=~_|$])" };
|
||||
static constexpr size_t TaskbarMinProgress{ 10 };
|
||||
|
||||
// You have to forward decl the ICoreSettings here, instead of including the header.
|
||||
// If you include the header, there will be compilation errors with other
|
||||
|
||||
@@ -46,9 +46,6 @@
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\renderer\dx\lib\dx.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\audio\midi\lib\midi.vcxproj">
|
||||
<Project>{3c67784e-1453-49c2-9660-483e2cc7f7ad}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -338,7 +338,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
auto lifetime = get_strong();
|
||||
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(WindowRoot().GetHostingWindow()) };
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(Appearance().WindowRoot().GetHostingWindow()) };
|
||||
auto file = co_await OpenImagePicker(parentHwnd);
|
||||
if (!file.empty())
|
||||
{
|
||||
|
||||
@@ -74,6 +74,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void CurrentColorScheme(const Editor::ColorSchemeViewModel& val);
|
||||
|
||||
WINRT_PROPERTY(bool, IsDefault, false);
|
||||
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
|
||||
|
||||
// These settings are not defined in AppearanceConfig, so we grab them
|
||||
// from the source profile itself. The reason we still want them in the
|
||||
@@ -133,7 +134,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
DEPENDENCY_PROPERTY(Editor::AppearanceViewModel, Appearance);
|
||||
WINRT_PROPERTY(Editor::ProfileViewModel, SourceProfile, nullptr);
|
||||
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
|
||||
|
||||
GETSET_BINDABLE_ENUM_SETTING(BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch, Appearance().BackgroundImageStretchMode);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
void ClearColorScheme();
|
||||
ColorSchemeViewModel CurrentColorScheme;
|
||||
Windows.Foundation.Collections.IObservableVector<ColorSchemeViewModel> SchemesList;
|
||||
IHostedInWindow WindowRoot; // necessary to send the right HWND into the file picker dialogs.
|
||||
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, FontFace);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Single, FontSize);
|
||||
@@ -58,7 +59,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
Appearances();
|
||||
AppearanceViewModel Appearance;
|
||||
ProfileViewModel SourceProfile;
|
||||
IHostedInWindow WindowRoot;
|
||||
static Windows.UI.Xaml.DependencyProperty AppearanceProperty { get; };
|
||||
|
||||
Boolean UsingMonospaceFont { get; };
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
inline constexpr uint8_t ColorTableDivider{ 8 };
|
||||
inline constexpr uint8_t ColorTableSize{ 16 };
|
||||
inline static constexpr uint8_t ColorTableDivider{ 8 };
|
||||
inline static constexpr uint8_t ColorTableSize{ 16 };
|
||||
|
||||
inline constexpr std::wstring_view ForegroundColorTag{ L"Foreground" };
|
||||
inline constexpr std::wstring_view BackgroundColorTag{ L"Background" };
|
||||
inline constexpr std::wstring_view CursorColorTag{ L"CursorColor" };
|
||||
inline constexpr std::wstring_view SelectionBackgroundColorTag{ L"SelectionBackground" };
|
||||
inline static constexpr std::wstring_view ForegroundColorTag{ L"Foreground" };
|
||||
inline static constexpr std::wstring_view BackgroundColorTag{ L"Background" };
|
||||
inline static constexpr std::wstring_view CursorColorTag{ L"CursorColor" };
|
||||
inline static constexpr std::wstring_view SelectionBackgroundColorTag{ L"SelectionBackground" };
|
||||
|
||||
struct ColorSchemeViewModel : ColorSchemeViewModelT<ColorSchemeViewModel>, ViewModelHelper<ColorSchemeViewModel>
|
||||
{
|
||||
|
||||
@@ -43,9 +43,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
constexpr std::wstring_view systemThemeName{ L"system" };
|
||||
constexpr std::wstring_view darkThemeName{ L"dark" };
|
||||
constexpr std::wstring_view lightThemeName{ L"light" };
|
||||
constexpr std::wstring_view legacySystemThemeName{ L"legacySystem" };
|
||||
constexpr std::wstring_view legacyDarkThemeName{ L"legacyDark" };
|
||||
constexpr std::wstring_view legacyLightThemeName{ L"legacyLight" };
|
||||
|
||||
GlobalAppearanceViewModel::GlobalAppearanceViewModel(Model::GlobalAppSettings globalSettings) :
|
||||
_GlobalSettings{ globalSettings },
|
||||
@@ -251,18 +248,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
return RS_(L"Globals_ThemeSystem/Content");
|
||||
}
|
||||
else if (theme.Name() == legacyDarkThemeName)
|
||||
{
|
||||
return RS_(L"Globals_ThemeDarkLegacy/Content");
|
||||
}
|
||||
else if (theme.Name() == legacyLightThemeName)
|
||||
{
|
||||
return RS_(L"Globals_ThemeLightLegacy/Content");
|
||||
}
|
||||
else if (theme.Name() == legacySystemThemeName)
|
||||
{
|
||||
return RS_(L"Globals_ThemeSystemLegacy/Content");
|
||||
}
|
||||
return theme.Name();
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
lastBreadcrumb = _breadcrumbs.GetAt(size - 1);
|
||||
}
|
||||
|
||||
// Collect all the values out of the old nav view item source
|
||||
auto menuItems{ SettingsNav().MenuItems() };
|
||||
|
||||
// We'll remove a bunch of items and iterate over it twice.
|
||||
@@ -157,14 +156,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}),
|
||||
menuItemsSTL.end());
|
||||
|
||||
// Now, we've got a list of just the static entries again. Lets take
|
||||
// those and stick them back into a new winrt vector, and set that as
|
||||
// the source again.
|
||||
//
|
||||
// By setting MenuItemsSource in its entirety, rather than manipulating
|
||||
// MenuItems, we avoid a crash in WinUI.
|
||||
auto newSource = winrt::single_threaded_vector<IInspectable>(std::move(menuItemsSTL));
|
||||
SettingsNav().MenuItemsSource(newSource);
|
||||
menuItems.ReplaceAll(menuItemsSTL);
|
||||
|
||||
// Repopulate profile-related menu items
|
||||
_InitializeProfilesList();
|
||||
@@ -217,7 +209,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// Couldn't find the selected item, fallback to first menu item
|
||||
// This happens when the selected item was a profile which doesn't exist in the new configuration
|
||||
// We can use menuItemsSTL here because the only things they miss are profile entries.
|
||||
const auto& firstItem{ SettingsNav().MenuItems().GetAt(0).as<MUX::Controls::NavigationViewItem>() };
|
||||
const auto& firstItem{ menuItemsSTL.at(0).as<MUX::Controls::NavigationViewItem>() };
|
||||
SettingsNav().SelectedItem(firstItem);
|
||||
_Navigate(unbox_value<hstring>(firstItem.Tag()), BreadcrumbSubPage::None);
|
||||
}
|
||||
@@ -356,14 +348,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto currentPage = profile.CurrentPage();
|
||||
if (currentPage == ProfileSubPage::Base)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), profile);
|
||||
_breadcrumbs.Clear();
|
||||
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, breadcrumbText, BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
}
|
||||
else if (currentPage == ProfileSubPage::Appearance)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Appearance>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Appearance>(), profile);
|
||||
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Appearance/Header"), BreadcrumbSubPage::Profile_Appearance);
|
||||
_breadcrumbs.Append(crumb);
|
||||
}
|
||||
@@ -408,12 +400,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
else if (clickedItemTag == globalProfileTag)
|
||||
{
|
||||
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone) };
|
||||
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes(), *this);
|
||||
profileVM.IsBaseLayer(true);
|
||||
|
||||
_SetupProfileEventHandling(profileVM);
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<implementation::NavigateToProfileArgs>(profileVM, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), profileVM);
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_ProfileDefaults/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
|
||||
@@ -465,7 +457,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
_SetupProfileEventHandling(profile);
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), profile);
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(profile), profile.Name(), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
|
||||
@@ -535,17 +527,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void MainPage::_InitializeProfilesList()
|
||||
{
|
||||
const auto& itemSource{ SettingsNav().MenuItemsSource() };
|
||||
if (!itemSource)
|
||||
{
|
||||
// There wasn't a MenuItemsSource set yet? The only way that's
|
||||
// possible is if we haven't used
|
||||
// _MoveXamlParsedNavItemsIntoItemSource to move the hardcoded menu
|
||||
// entries from XAML into our runtime menu item source. Do that now.
|
||||
|
||||
_MoveXamlParsedNavItemsIntoItemSource();
|
||||
}
|
||||
const auto menuItems = SettingsNav().MenuItemsSource().try_as<IVector<IInspectable>>();
|
||||
const auto menuItems = SettingsNav().MenuItems();
|
||||
|
||||
// Manually create a NavigationViewItem for each profile
|
||||
// and keep a reference to them in a map so that we
|
||||
@@ -556,7 +538,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (!profile.Deleted())
|
||||
{
|
||||
auto profileVM = _viewModelForProfile(profile, _settingsClone);
|
||||
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes(), *this);
|
||||
auto navItem = _CreateProfileNavViewItem(profileVM);
|
||||
menuItems.Append(navItem);
|
||||
}
|
||||
@@ -575,42 +557,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
menuItems.Append(addProfileItem);
|
||||
}
|
||||
|
||||
// BODGY
|
||||
// Does the very wacky business of moving all our MenuItems that we
|
||||
// hardcoded in XAML into a runtime MenuItemsSource. We'll then use _that_
|
||||
// MenuItemsSource as the source for our nav view entries instead. This
|
||||
// lets us hardcode the initial entries in precompiled XAML, but then adjust
|
||||
// the items at runtime. Without using a MenuItemsSource, the NavView just
|
||||
// crashes when items are removed (see GH#13673)
|
||||
void MainPage::_MoveXamlParsedNavItemsIntoItemSource()
|
||||
{
|
||||
if (SettingsNav().MenuItemsSource())
|
||||
{
|
||||
// We've already copied over the original items to a source. We can
|
||||
// just skip this now.
|
||||
return;
|
||||
}
|
||||
|
||||
auto menuItems{ SettingsNav().MenuItems() };
|
||||
// Remove all the existing items, and move them to a separate vector
|
||||
// that we'll use as a MenuItemsSource. By doing this, we avoid a WinUI
|
||||
// bug (MUX#6302) where modifying the NavView.Items() directly causes a
|
||||
// crash. By leaving these static entries in XAML, we maintain the
|
||||
// benefit of instantiating them from the XBF, rather than at runtime.
|
||||
//
|
||||
// --> Copy it into an STL vector to simplify our code and reduce COM overhead.
|
||||
std::vector<IInspectable> menuItemsSTL(menuItems.Size(), nullptr);
|
||||
menuItems.GetMany(0, menuItemsSTL);
|
||||
|
||||
auto newSource = winrt::single_threaded_vector<IInspectable>(std::move(menuItemsSTL));
|
||||
SettingsNav().MenuItemsSource(newSource);
|
||||
}
|
||||
|
||||
void MainPage::_CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile)
|
||||
{
|
||||
const auto newProfile{ profile ? profile : _settingsClone.CreateNewProfile() };
|
||||
const auto profileViewModel{ _viewModelForProfile(newProfile, _settingsClone) };
|
||||
profileViewModel.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
profileViewModel.SetupAppearances(_colorSchemesPageVM.AllColorSchemes(), *this);
|
||||
const auto navItem{ _CreateProfileNavViewItem(profileViewModel) };
|
||||
SettingsNav().MenuItems().InsertAt(index, navItem);
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void _Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage);
|
||||
|
||||
void _UpdateBackgroundForMica();
|
||||
void _MoveXamlParsedNavItemsIntoItemSource();
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageViewModel _colorSchemesPageVM{ nullptr };
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:tsm="using:Microsoft.Terminal.Settings.Model"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
@@ -190,29 +189,13 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Margin="30,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Vertical">
|
||||
<TextBlock x:Uid="Settings_UnsavedSettingsWarning"
|
||||
Foreground="Goldenrod"
|
||||
TextAlignment="Left"
|
||||
Visibility="Collapsed" />
|
||||
<StackPanel VerticalAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
Spacing="4"
|
||||
Visibility="{x:Bind tsm:CascadiaSettings.IsPortableMode, Mode=OneTime}">
|
||||
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
Foreground="SlateBlue"
|
||||
Glyph="" />
|
||||
<TextBlock Foreground="SlateBlue">
|
||||
<Run x:Uid="Settings_PortableModeNote" />
|
||||
<Hyperlink x:Uid="Settings_PortableModeInfoLink">
|
||||
<Run x:Uid="Settings_PortableModeInfoLinkTextRun" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<TextBlock x:Uid="Settings_UnsavedSettingsWarning"
|
||||
Margin="30,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="Goldenrod"
|
||||
TextAlignment="Left"
|
||||
Visibility="Collapsed" />
|
||||
<StackPanel Margin="0,0,30,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
|
||||
@@ -353,6 +353,7 @@
|
||||
</PRIResource>
|
||||
<OCResourceDirectory Include="Resources" />
|
||||
<None Include="$(ProjectName).def" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
|
||||
@@ -248,6 +248,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
_unfocusedAppearanceViewModel = winrt::make<implementation::AppearanceViewModel>(_profile.UnfocusedAppearance().try_as<AppearanceConfig>());
|
||||
_unfocusedAppearanceViewModel.SchemesList(DefaultAppearance().SchemesList());
|
||||
_unfocusedAppearanceViewModel.WindowRoot(DefaultAppearance().WindowRoot());
|
||||
|
||||
_NotifyChanges(L"UnfocusedAppearance", L"HasUnfocusedAppearance", L"ShowUnfocusedAppearance");
|
||||
}
|
||||
@@ -349,12 +350,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_DeleteProfileHandlers(*this, *deleteProfileArgs);
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetupAppearances(Windows::Foundation::Collections::IObservableVector<Editor::ColorSchemeViewModel> schemesList)
|
||||
void ProfileViewModel::SetupAppearances(Windows::Foundation::Collections::IObservableVector<Editor::ColorSchemeViewModel> schemesList, Editor::IHostedInWindow windowRoot)
|
||||
{
|
||||
DefaultAppearance().SchemesList(schemesList);
|
||||
DefaultAppearance().WindowRoot(windowRoot);
|
||||
if (UnfocusedAppearance())
|
||||
{
|
||||
UnfocusedAppearance().SchemesList(schemesList);
|
||||
UnfocusedAppearance().WindowRoot(windowRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "DeleteProfileEventArgs.g.h"
|
||||
#include "NavigateToProfileArgs.g.h"
|
||||
#include "ProfileViewModel.g.h"
|
||||
#include "Utils.h"
|
||||
#include "ViewModelHelpers.h"
|
||||
@@ -12,21 +11,6 @@
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct NavigateToProfileArgs : NavigateToProfileArgsT<NavigateToProfileArgs>
|
||||
{
|
||||
public:
|
||||
NavigateToProfileArgs(ProfileViewModel profile, Editor::IHostedInWindow windowRoot) :
|
||||
_Profile(profile),
|
||||
_WindowRoot(windowRoot) {}
|
||||
|
||||
Editor::IHostedInWindow WindowRoot() const noexcept { return _WindowRoot; }
|
||||
Editor::ProfileViewModel Profile() const noexcept { return _Profile; }
|
||||
|
||||
private:
|
||||
Editor::IHostedInWindow _WindowRoot;
|
||||
Editor::ProfileViewModel _Profile{ nullptr };
|
||||
};
|
||||
|
||||
struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
|
||||
{
|
||||
public:
|
||||
@@ -39,7 +23,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
Model::TerminalSettings TermSettings() const;
|
||||
void DeleteProfile();
|
||||
|
||||
void SetupAppearances(Windows::Foundation::Collections::IObservableVector<Editor::ColorSchemeViewModel> schemesList);
|
||||
void SetupAppearances(Windows::Foundation::Collections::IObservableVector<Editor::ColorSchemeViewModel> schemesList, Editor::IHostedInWindow windowRoot);
|
||||
|
||||
// bell style bits
|
||||
bool IsBellStyleFlagSet(const uint32_t flag);
|
||||
@@ -107,6 +91,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
WINRT_PROPERTY(bool, IsBaseLayer, false);
|
||||
WINRT_PROPERTY(bool, FocusDeleteButton, false);
|
||||
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
|
||||
GETSET_BINDABLE_ENUM_SETTING(AntiAliasingMode, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode);
|
||||
GETSET_BINDABLE_ENUM_SETTING(CloseOnExitMode, Microsoft::Terminal::Settings::Model::CloseOnExitMode, CloseOnExit);
|
||||
GETSET_BINDABLE_ENUM_SETTING(ScrollState, Microsoft::Terminal::Control::ScrollbarState, ScrollState);
|
||||
|
||||
@@ -14,12 +14,6 @@ import "ColorSchemesPageViewModel.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass NavigateToProfileArgs
|
||||
{
|
||||
ProfileViewModel Profile { get; };
|
||||
IHostedInWindow WindowRoot { get; };
|
||||
}
|
||||
|
||||
runtimeclass DeleteProfileEventArgs
|
||||
{
|
||||
Guid ProfileGuid { get; };
|
||||
@@ -41,7 +35,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<ProfileViewModel, DeleteProfileEventArgs> DeleteProfile;
|
||||
|
||||
void SetupAppearances(Windows.Foundation.Collections.IObservableVector<ColorSchemeViewModel> schemesList);
|
||||
void SetupAppearances(Windows.Foundation.Collections.IObservableVector<ColorSchemeViewModel> schemesList, IHostedInWindow windowRoot);
|
||||
|
||||
void SetAcrylicOpacityPercentageValue(Double value);
|
||||
void SetPadding(Double value);
|
||||
|
||||
@@ -28,9 +28,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Profiles_Appearance::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToProfileArgs>();
|
||||
_Profile = args.Profile();
|
||||
_windowRoot = args.WindowRoot();
|
||||
_Profile = e.Parameter().as<Editor::ProfileViewModel>();
|
||||
|
||||
// generate the font list, if we don't have one
|
||||
if (_Profile.CompleteFontList() || !_Profile.MonospaceFontList())
|
||||
|
||||
@@ -19,8 +19,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void CreateUnfocusedAppearance_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void DeleteUnfocusedAppearance_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
|
||||
Editor::IHostedInWindow WindowRoot() { return _windowRoot; };
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
|
||||
|
||||
@@ -28,7 +26,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
Microsoft::Terminal::Control::TermControl _previewControl;
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _AppearanceViewModelChangedRevoker;
|
||||
Editor::IHostedInWindow _windowRoot;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
Profiles_Appearance();
|
||||
ProfileViewModel Profile { get; };
|
||||
IHostedInWindow WindowRoot { get; };
|
||||
|
||||
Windows.UI.Xaml.Controls.Slider OpacitySlider { get; };
|
||||
}
|
||||
|
||||
@@ -56,8 +56,7 @@
|
||||
</Border>
|
||||
|
||||
<local:Appearances Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
|
||||
SourceProfile="{x:Bind Profile, Mode=OneWay}"
|
||||
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
|
||||
SourceProfile="{x:Bind Profile, Mode=OneWay}" />
|
||||
|
||||
<!-- Grouping: Transparency -->
|
||||
<StackPanel Style="{StaticResource PivotStackStyle}">
|
||||
@@ -175,8 +174,7 @@
|
||||
</StackPanel>
|
||||
<local:Appearances Appearance="{x:Bind Profile.UnfocusedAppearance, Mode=OneWay}"
|
||||
SourceProfile="{x:Bind Profile, Mode=OneWay}"
|
||||
Visibility="{x:Bind Profile.ShowUnfocusedAppearance, Mode=OneWay}"
|
||||
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
|
||||
Visibility="{x:Bind Profile.ShowUnfocusedAppearance, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -29,9 +29,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Profiles_Base::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToProfileArgs>();
|
||||
_Profile = args.Profile();
|
||||
_windowRoot = args.WindowRoot();
|
||||
_Profile = e.Parameter().as<Editor::ProfileViewModel>();
|
||||
|
||||
// Check the use parent directory box if the starting directory is empty
|
||||
if (_Profile.StartingDirectory().empty())
|
||||
@@ -87,7 +85,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
};
|
||||
|
||||
static constexpr winrt::guid clientGuidExecutables{ 0x2E7E4331, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(_windowRoot.GetHostingWindow()) };
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(winrt::get_self<ProfileViewModel>(_Profile)->WindowRoot().GetHostingWindow()) };
|
||||
auto path = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExecutables));
|
||||
try
|
||||
@@ -111,7 +109,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
auto lifetime = get_strong();
|
||||
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(_windowRoot.GetHostingWindow()) };
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(winrt::get_self<ProfileViewModel>(_Profile)->WindowRoot().GetHostingWindow()) };
|
||||
auto file = co_await OpenImagePicker(parentHwnd);
|
||||
if (!file.empty())
|
||||
{
|
||||
@@ -122,7 +120,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
fire_and_forget Profiles_Base::StartingDirectory_Click(const IInspectable&, const RoutedEventArgs&)
|
||||
{
|
||||
auto lifetime = get_strong();
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(_windowRoot.GetHostingWindow()) };
|
||||
const auto parentHwnd{ reinterpret_cast<HWND>(winrt::get_self<ProfileViewModel>(_Profile)->WindowRoot().GetHostingWindow()) };
|
||||
auto folder = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
|
||||
static constexpr winrt::guid clientGuidFolderPicker{ 0xAADAA433, 0xB04D, 0x4BAE, { 0xB1, 0xEA, 0x1E, 0x6C, 0xD1, 0xCD, 0xA6, 0x8B } };
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidFolderPicker));
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
private:
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
Editor::IHostedInWindow _windowRoot;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -536,27 +536,15 @@
|
||||
</data>
|
||||
<data name="Globals_ThemeDark.Content" xml:space="preserve">
|
||||
<value>Dark</value>
|
||||
<comment>An option to choose from for the "theme" setting. When selected, the app is in dark theme and darker colors are used throughout the app.</comment>
|
||||
<comment>An option to choose from for the "tab width mode" setting. When selected, the app is in dark theme and darker colors are used throughout the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ThemeSystem.Content" xml:space="preserve">
|
||||
<value>Use Windows theme</value>
|
||||
<comment>An option to choose from for the "theme" setting. When selected, the app uses the theme selected in the Windows operating system.</comment>
|
||||
<comment>An option to choose from for the "tab width mode" setting. When selected, the app uses the theme selected in the Windows operating system.</comment>
|
||||
</data>
|
||||
<data name="Globals_ThemeLight.Content" xml:space="preserve">
|
||||
<value>Light</value>
|
||||
<comment>An option to choose from for the "theme" setting. When selected, the app is in light theme and lighter colors are used throughout the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ThemeDarkLegacy.Content" xml:space="preserve">
|
||||
<value>Dark (Legacy)</value>
|
||||
<comment>An option to choose from for the "theme" setting. When selected, the app is in dark theme and darker colors are used throughout the app. This is an older version of the "dark" theme</comment>
|
||||
</data>
|
||||
<data name="Globals_ThemeSystemLegacy.Content" xml:space="preserve">
|
||||
<value>Use Windows theme (Legacy)</value>
|
||||
<comment>An option to choose from for the "theme" setting. When selected, the app uses the theme selected in the Windows operating system. This is an older version of the "Use Windows theme" theme</comment>
|
||||
</data>
|
||||
<data name="Globals_ThemeLightLegacy.Content" xml:space="preserve">
|
||||
<value>Light (Legacy)</value>
|
||||
<comment>An option to choose from for the "theme" setting. When selected, the app is in light theme and lighter colors are used throughout the app. This is an older version of the "light" theme</comment>
|
||||
<comment>An option to choose from for the "tab width mode" setting. When selected, the app is in light theme and lighter colors are used throughout the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_WordDelimiters.Header" xml:space="preserve">
|
||||
<value>Word delimiters</value>
|
||||
@@ -1581,16 +1569,4 @@
|
||||
<value>Warn when closing more than one tab</value>
|
||||
<comment>Header for a control to toggle whether to show a confirm dialog box when closing the application with multiple tabs open.</comment>
|
||||
</data>
|
||||
<data name="Settings_PortableModeNote.Text" xml:space="preserve">
|
||||
<value>Windows Terminal is running in portable mode.</value>
|
||||
<comment>A disclaimer that indicates that Terminal is running in a mode that saves settings to a different folder.</comment>
|
||||
</data>
|
||||
<data name="Settings_PortableModeInfoLink.NavigateUri" xml:space="preserve">
|
||||
<value>https://go.microsoft.com/fwlink/?linkid=2229086</value>
|
||||
<comment>{Locked}</comment>
|
||||
</data>
|
||||
<data name="Settings_PortableModeInfoLinkTextRun.Text" xml:space="preserve">
|
||||
<value>Learn more.</value>
|
||||
<comment>A hyperlink displayed near Settings_PortableModeNote.Text that the user can follow for more information.</comment>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
4
src/cascadia/TerminalSettingsEditor/packages.config
Normal file
4
src/cascadia/TerminalSettingsEditor/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -1006,7 +1006,7 @@ winrt::hstring CascadiaSettings::ApplicationDisplayName()
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
return IsPortableMode() ? RS_(L"ApplicationDisplayNamePortable") : RS_(L"ApplicationDisplayNameUnpackaged");
|
||||
return RS_(L"ApplicationDisplayNameUnpackaged");
|
||||
}
|
||||
|
||||
winrt::hstring CascadiaSettings::ApplicationVersion()
|
||||
@@ -1015,7 +1015,12 @@ winrt::hstring CascadiaSettings::ApplicationVersion()
|
||||
{
|
||||
const auto package{ winrt::Windows::ApplicationModel::Package::Current() };
|
||||
const auto version{ package.Id().Version() };
|
||||
winrt::hstring formatted{ wil::str_printf<std::wstring>(L"%u.%u.%u.%u", version.Major, version.Minor, version.Build, version.Revision) };
|
||||
// As of about 2022, the ones digit of the Build of our version is a
|
||||
// placeholder value to differentiate the Windows 10 build from the
|
||||
// Windows 11 build. Let's trim that out. For additional clarity,
|
||||
// let's omit the Revision, which _must_ be .0, and doesn't provide any
|
||||
// value to report.
|
||||
winrt::hstring formatted{ wil::str_printf<std::wstring>(L"%u.%u.%u", version.Major, version.Minor, version.Build / 10) };
|
||||
return formatted;
|
||||
}
|
||||
CATCH_LOG();
|
||||
@@ -1082,21 +1087,7 @@ bool CascadiaSettings::IsDefaultTerminalAvailable() noexcept
|
||||
DWORDLONG dwlConditionMask = 0;
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
|
||||
|
||||
if (VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isOtherwiseAvailable = [] {
|
||||
wil::unique_hkey key;
|
||||
const auto lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\SystemSettings\\SettingId\\SystemSettings_Developer_Mode_Setting_DefaultTerminalApp",
|
||||
0,
|
||||
KEY_READ,
|
||||
&key);
|
||||
return static_cast<bool>(key) && ERROR_SUCCESS == lResult;
|
||||
}();
|
||||
return isOtherwiseAvailable;
|
||||
return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
|
||||
}
|
||||
|
||||
bool CascadiaSettings::IsDefaultTerminalSet() noexcept
|
||||
|
||||
@@ -105,7 +105,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
static winrt::hstring DefaultSettingsPath();
|
||||
static winrt::hstring ApplicationDisplayName();
|
||||
static winrt::hstring ApplicationVersion();
|
||||
static bool IsPortableMode();
|
||||
static void ExportFile(winrt::hstring path, winrt::hstring content);
|
||||
|
||||
CascadiaSettings() noexcept = default;
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
static String SettingsPath { get; };
|
||||
static String DefaultSettingsPath { get; };
|
||||
static Boolean IsPortableMode { get; };
|
||||
|
||||
static String ApplicationDisplayName { get; };
|
||||
static String ApplicationVersion { get; };
|
||||
|
||||
@@ -52,9 +52,6 @@ static constexpr std::string_view ThemesKey{ "themes" };
|
||||
constexpr std::wstring_view systemThemeName{ L"system" };
|
||||
constexpr std::wstring_view darkThemeName{ L"dark" };
|
||||
constexpr std::wstring_view lightThemeName{ L"light" };
|
||||
constexpr std::wstring_view legacySystemThemeName{ L"legacySystem" };
|
||||
constexpr std::wstring_view legacyDarkThemeName{ L"legacyDark" };
|
||||
constexpr std::wstring_view legacyLightThemeName{ L"legacyLight" };
|
||||
|
||||
static constexpr std::wstring_view jsonExtension{ L".json" };
|
||||
static constexpr std::wstring_view FragmentsSubDirectory{ L"\\Fragments" };
|
||||
@@ -565,9 +562,8 @@ void SettingsLoader::_parse(const OriginTag origin, const winrt::hstring& source
|
||||
{
|
||||
if (const auto theme = Theme::FromJson(themeJson))
|
||||
{
|
||||
const auto& name{ theme->Name() };
|
||||
if (origin != OriginTag::InBox &&
|
||||
(name == systemThemeName || name == lightThemeName || name == darkThemeName || name == legacySystemThemeName || name == legacyDarkThemeName || name == legacyLightThemeName))
|
||||
(theme->Name() == systemThemeName || theme->Name() == lightThemeName || theme->Name() == darkThemeName))
|
||||
{
|
||||
// If the theme didn't come from the in-box themes, and its
|
||||
// name was one of the reserved names, then just ignore it.
|
||||
@@ -826,7 +822,7 @@ try
|
||||
// read settings.json from the Release stable file path if it exists.
|
||||
// Otherwise use default settings file provided from original settings file
|
||||
bool releaseSettingExists = false;
|
||||
if (firstTimeSetup && !IsPortableMode())
|
||||
if (firstTimeSetup)
|
||||
{
|
||||
#if defined(WT_BRANDING_PREVIEW)
|
||||
{
|
||||
@@ -957,16 +953,10 @@ void CascadiaSettings::_researchOnLoad()
|
||||
// light: 1
|
||||
// dark: 2
|
||||
// a custom theme: 3
|
||||
// system (legacy): 4
|
||||
// light (legacy): 5
|
||||
// dark (legacy): 6
|
||||
const auto themeChoice = themeInUse == L"system" ? 0 :
|
||||
themeInUse == L"light" ? 1 :
|
||||
themeInUse == L"dark" ? 2 :
|
||||
themeInUse == L"legacyDark" ? 4 :
|
||||
themeInUse == L"legacyLight" ? 5 :
|
||||
themeInUse == L"legacySystem" ? 6 :
|
||||
3;
|
||||
const auto themeChoice = themeInUse == L"system" ? 0 :
|
||||
themeInUse == L"light" ? 1 :
|
||||
themeInUse == L"dark" ? 2 :
|
||||
3;
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hSettingsModelProvider,
|
||||
@@ -1170,11 +1160,6 @@ winrt::hstring CascadiaSettings::SettingsPath()
|
||||
return winrt::hstring{ _settingsPath().native() };
|
||||
}
|
||||
|
||||
bool CascadiaSettings::IsPortableMode()
|
||||
{
|
||||
return Model::IsPortableMode();
|
||||
}
|
||||
|
||||
winrt::hstring CascadiaSettings::DefaultSettingsPath()
|
||||
{
|
||||
// Both of these posts suggest getting the path to the exe, then removing
|
||||
|
||||
@@ -99,7 +99,7 @@ bool DefaultTerminal::HasCurrent()
|
||||
|
||||
void DefaultTerminal::Current(const Model::DefaultTerminal& term)
|
||||
{
|
||||
THROW_IF_FAILED(DelegationConfig::s_SetDefaultByPackage(winrt::get_self<DefaultTerminal>(term)->_pkg));
|
||||
THROW_IF_FAILED(DelegationConfig::s_SetDefaultByPackage(winrt::get_self<DefaultTerminal>(term)->_pkg, true));
|
||||
|
||||
TraceLoggingWrite(g_hSettingsModelProvider,
|
||||
"DefaultTerminalChanged",
|
||||
|
||||
@@ -21,6 +21,6 @@ Author(s):
|
||||
// will become disconnected from user settings.
|
||||
// {2bde4a90-d05f-401c-9492-e40884ead1d8}
|
||||
// uuidv5 properties: name format is UTF-16LE bytes
|
||||
inline constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } };
|
||||
static constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } };
|
||||
|
||||
winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile> CreateDynamicProfile(const std::wstring_view& name);
|
||||
|
||||
@@ -15,34 +15,14 @@
|
||||
static constexpr std::string_view Utf8Bom{ "\xEF\xBB\xBF", 3 };
|
||||
static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" };
|
||||
static constexpr std::wstring_view ReleaseSettingsFolder{ L"Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\" };
|
||||
static constexpr std::wstring_view PortableModeMarkerFile{ L".portable" };
|
||||
static constexpr std::wstring_view PortableModeSettingsFolder{ L"settings" };
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model
|
||||
{
|
||||
// Returns a path like C:\Users\<username>\AppData\Local\Packages\<packagename>\LocalState
|
||||
// You can put your settings.json or state.json in this directory.
|
||||
bool IsPortableMode()
|
||||
{
|
||||
static auto portableMode = []() {
|
||||
std::filesystem::path modulePath{ wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle()) };
|
||||
modulePath.replace_filename(PortableModeMarkerFile);
|
||||
return std::filesystem::exists(modulePath);
|
||||
}();
|
||||
return portableMode;
|
||||
}
|
||||
|
||||
std::filesystem::path GetBaseSettingsPath()
|
||||
{
|
||||
static auto baseSettingsPath = []() {
|
||||
if (!IsPackaged() && IsPortableMode())
|
||||
{
|
||||
std::filesystem::path modulePath{ wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle()) };
|
||||
modulePath.replace_filename(PortableModeSettingsFolder);
|
||||
std::filesystem::create_directories(modulePath);
|
||||
return modulePath;
|
||||
}
|
||||
|
||||
wil::unique_cotaskmem_string localAppDataFolder;
|
||||
// KF_FLAG_FORCE_APP_DATA_REDIRECTION, when engaged, causes SHGet... to return
|
||||
// the new AppModel paths (Packages/xxx/RoamingState, etc.) for standard path requests.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model
|
||||
{
|
||||
bool IsPortableMode();
|
||||
std::filesystem::path GetBaseSettingsPath();
|
||||
std::filesystem::path GetReleaseSettingsPath();
|
||||
std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly = false, FILETIME* lastWriteTime = nullptr);
|
||||
|
||||
@@ -16,6 +16,6 @@ Author(s):
|
||||
|
||||
#pragma once
|
||||
|
||||
inline constexpr std::wstring_view WslGeneratorNamespace{ L"Windows.Terminal.Wsl" };
|
||||
inline constexpr std::wstring_view AzureGeneratorNamespace{ L"Windows.Terminal.Azure" };
|
||||
inline constexpr std::wstring_view PowershellCoreGeneratorNamespace{ L"Windows.Terminal.PowershellCore" };
|
||||
static constexpr std::wstring_view WslGeneratorNamespace{ L"Windows.Terminal.Wsl" };
|
||||
static constexpr std::wstring_view AzureGeneratorNamespace{ L"Windows.Terminal.Azure" };
|
||||
static constexpr std::wstring_view PowershellCoreGeneratorNamespace{ L"Windows.Terminal.PowershellCore" };
|
||||
|
||||
@@ -126,10 +126,6 @@
|
||||
<data name="SplitPaneParentCommandName" xml:space="preserve">
|
||||
<value>Split Pane...</value>
|
||||
</data>
|
||||
<data name="ApplicationDisplayNamePortable" xml:space="preserve">
|
||||
<value>Terminal (Portable)</value>
|
||||
<comment>This display name is used when the Terminal application is running in a "portable" mode, where settings are not stored in a shared location.</comment>
|
||||
</data>
|
||||
<data name="ApplicationDisplayNameUnpackaged" xml:space="preserve">
|
||||
<value>Terminal (Unpackaged)</value>
|
||||
<comment>This display name is used when the application's name cannot be determined</comment>
|
||||
|
||||
@@ -42,9 +42,6 @@ std::wstring VsDevCmdGenerator::GetProfileCommandLine(const VsSetupConfiguration
|
||||
commandLine.reserve(256);
|
||||
commandLine.append(LR"(cmd.exe /k ")");
|
||||
commandLine.append(GetDevCmdScriptPath(instance));
|
||||
// The "-startdir" parameter will prevent "vsdevcmd" from automatically
|
||||
// setting the shell path so the path in the profile will be used instead.
|
||||
commandLine.append(LR"(" -startdir=none)");
|
||||
#if defined(_M_ARM64)
|
||||
commandLine.append(LR"(" -arch=arm64 -host_arch=x64)");
|
||||
#elif defined(_M_AMD64)
|
||||
|
||||
@@ -316,36 +316,6 @@
|
||||
"background": "terminalBackground",
|
||||
"unfocusedBackground": "#00000000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "legacyDark",
|
||||
"tab": {
|
||||
"background": null,
|
||||
"unfocusedBackground": null
|
||||
},
|
||||
"window": {
|
||||
"applicationTheme": "dark"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "legacyLight",
|
||||
"tab": {
|
||||
"background": null,
|
||||
"unfocusedBackground": null
|
||||
},
|
||||
"window": {
|
||||
"applicationTheme": "light"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "legacySystem",
|
||||
"tab": {
|
||||
"background": null,
|
||||
"unfocusedBackground": null
|
||||
},
|
||||
"window": {
|
||||
"applicationTheme": "system"
|
||||
},
|
||||
}
|
||||
],
|
||||
"actions":
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
<ItemGroup>
|
||||
<Manifest Include="WindowsTerminal.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<!-- Dependencies -->
|
||||
<ItemGroup>
|
||||
<!-- Even though we do have proper recursive dependencies, we want to keep some of these here
|
||||
|
||||
4
src/cascadia/WindowsTerminal/packages.config
Normal file
4
src/cascadia/WindowsTerminal/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -50,8 +50,8 @@ namespace WindowsTerminal.UIA.Tests.Elements
|
||||
this.context = context;
|
||||
|
||||
// If running locally, set WTPath to where we can find a loose deployment of Windows Terminal
|
||||
// On the build machines, the scripts lay it out at the terminal-0.0.1.0\ subfolder of the test deployment directory
|
||||
string path = Path.GetFullPath(Path.Combine(context.TestDeploymentDir, @"terminal-0.0.1.0\WindowsTerminal.exe"));
|
||||
// On the build machines, the scripts lay it out at the appx\ subfolder of the test deployment directory
|
||||
string path = Path.GetFullPath(Path.Combine(context.TestDeploymentDir, @"appx\WindowsTerminal.exe"));
|
||||
if (context.Properties.Contains("WTPath"))
|
||||
{
|
||||
path = (string)context.Properties["WTPath"];
|
||||
|
||||
@@ -4,10 +4,10 @@ Licensed under the MIT license.
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
inline constexpr int32_t WindowingBehaviorUseCurrent{ 0 };
|
||||
inline constexpr int32_t WindowingBehaviorUseNew{ -1 };
|
||||
inline constexpr int32_t WindowingBehaviorUseExisting{ -2 };
|
||||
inline constexpr int32_t WindowingBehaviorUseAnyExisting{ -3 };
|
||||
inline constexpr int32_t WindowingBehaviorUseName{ -4 };
|
||||
constexpr int32_t WindowingBehaviorUseCurrent{ 0 };
|
||||
constexpr int32_t WindowingBehaviorUseNew{ -1 };
|
||||
constexpr int32_t WindowingBehaviorUseExisting{ -2 };
|
||||
constexpr int32_t WindowingBehaviorUseAnyExisting{ -3 };
|
||||
constexpr int32_t WindowingBehaviorUseName{ -4 };
|
||||
|
||||
inline constexpr std::wstring_view QuakeWindowName{ L"_quake" };
|
||||
static constexpr std::wstring_view QuakeWindowName{ L"_quake" };
|
||||
|
||||
@@ -83,6 +83,13 @@
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.tests.props" />
|
||||
<Import Project="$(SolutionDir)src\common.nugetversions.targets" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- From Microsoft.UI.Xaml.targets -->
|
||||
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
|
||||
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
|
||||
<_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\runtimes\win10-$(Native-Platform)\native\"</_MUXBinRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<PreBuildEvent>
|
||||
<!-- Manually copy the Windows Terminal manifest to our project directory,
|
||||
|
||||
@@ -4,42 +4,6 @@
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
The Hybrid CRT model statically links the runtime and STL and dynamically
|
||||
links the UCRT instead of the VC++ CRT. The UCRT ships with Windows.
|
||||
WinAppSDK asserts that this is "supported according to the CRT maintainer."
|
||||
|
||||
This must come before Microsoft.Cpp.targets because it manipulates ClCompile.RuntimeLibrary.
|
||||
-->
|
||||
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and '$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and ('$(Configuration)'=='Release' or '$(Configuration)'=='AuditMode')">
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -81,26 +81,12 @@
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
We don't need to use HybridCRT for Fuzzing, so just skip it entirely.
|
||||
Fuzzing requires the address sanitizer runtime library plus the fuzzing
|
||||
harness. They're probably not compatible.
|
||||
|
||||
Audit, however, *does* require linking components built in Release mode...
|
||||
-->
|
||||
<ConfigurationSupportsHybridCRT Condition="'$(Configuration)'=='Fuzzing'">false</ConfigurationSupportsHybridCRT>
|
||||
<ConfigurationSupportsHybridCRT Condition="'$(ConfigurationSupportsHybridCRT)'==''">true</ConfigurationSupportsHybridCRT>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- For ALL build types-->
|
||||
<PropertyGroup Label="Configuration">
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
<EnableHybridCRT Condition="'$(EnableHybridCRT)'=='' and '$(ConfigurationSupportsHybridCRT)'=='true'">true</EnableHybridCRT>
|
||||
<UseCrtSDKReferenceStaticWarning Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReferenceStaticWarning>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
<!-- TAEF -->
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.Taef.10.60.210621002\build\Microsoft.Taef.targets" Condition="'$(TerminalTAEF)' == 'true' and Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.Taef.10.60.210621002\build\Microsoft.Taef.targets')" />
|
||||
|
||||
<!-- CppRestSDK -->
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\vcpkg-cpprestsdk.2.10.14\build\native\vcpkg-cpprestsdk.targets" Condition="'$(TerminalCppRestSDK)' == 'true' and Exists('$(MSBuildThisFileDirectory)..\packages\vcpkg-cpprestsdk.2.10.14\build\native\vcpkg-cpprestsdk.targets')" />
|
||||
|
||||
<!-- VCRTForwarders -->
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets" Condition="'$(TerminalVCRTForwarders)' == 'true' and Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" />
|
||||
|
||||
@@ -53,7 +56,7 @@
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="'$(TerminalVisualStudioSetup)' == 'true' and Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" />
|
||||
|
||||
<!-- WinUI (which depends on WebView2 as of 2.8.0) -->
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="'$(TerminalMUX)' == 'true' and Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="'$(TerminalMUX)' == 'true' and Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
||||
<!-- WIL (so widely used that this one does not have a TerminalWIL opt-in property; it is automatic) -->
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220201.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220201.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
@@ -76,6 +79,9 @@
|
||||
<!-- TAEF -->
|
||||
<Error Condition="'$(TerminalTAEF)' == 'true' AND !Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.Taef.10.60.210621002\build\Microsoft.Taef.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.Taef.10.60.210621002\build\Microsoft.Taef.targets'))" />
|
||||
|
||||
<!-- CppRestSDK -->
|
||||
<Error Condition="'$(TerminalCppRestSDK)' == 'true' AND !Exists('$(MSBuildThisFileDirectory)..\packages\vcpkg-cpprestsdk.2.10.14\build\native\vcpkg-cpprestsdk.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\vcpkg-cpprestsdk.2.10.14\build\native\vcpkg-cpprestsdk.targets'))" />
|
||||
|
||||
<!-- VCRTForwarders -->
|
||||
<Error Condition="'$(TerminalVCRTForwarders)' == 'true' AND !Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" />
|
||||
|
||||
@@ -86,7 +92,7 @@
|
||||
<Error Condition="'$(TerminalVisualStudioSetup)' == 'true' AND !Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets'))" />
|
||||
|
||||
<!-- WinUI (which depends on WebView2 as of 2.8.0) -->
|
||||
<Error Condition="'$(TerminalMUX)' == 'true' AND !Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="'$(TerminalMUX)' == 'true' AND !Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
|
||||
<!-- WIL (so widely used that this one does not have a TerminalWIL opt-in property; it is automatic) -->
|
||||
<Error Condition="!Exists('$(MSBuildThisFileDirectory)..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220201.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(MSBuildThisFileDirectory)..\packages\Microsoft.Windows.ImplementationLibrary.1.0.220201.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<WindowsStoreApp>true</WindowsStoreApp>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<UseCrtSDKReference Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReference> <!-- The SDK reference breaks the Hybrid CRT -->
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(OpenConsoleUniversalApp)'!='true'">
|
||||
<!-- Some of our projects include the cppwinrt build options to
|
||||
|
||||
@@ -67,15 +67,6 @@
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_LegacyConhost</name>
|
||||
<description>conhost should support ForceV2=false, and try to load conhostv1.dll</description>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>WindowsInbox</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_AtlasEngine</name>
|
||||
<description>If enabled, AtlasEngine is used by default</description>
|
||||
@@ -154,14 +145,4 @@
|
||||
<stage>AlwaysDisabled</stage>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_AzureConnectionInProc</name>
|
||||
<description>Host the AzureConnection inside Terminal rather than via TerminalAzBridge</description>
|
||||
<id>4661</id>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
</featureStaging>
|
||||
|
||||
@@ -52,27 +52,6 @@ class DefaultOutOfProcModuleWithRegistrationFlag : public OutOfProcModuleWithReg
|
||||
// Holds the wwinmain open until COM tells us there are no more server connections
|
||||
wil::unique_event _comServerExitEvent;
|
||||
|
||||
[[nodiscard]] static HRESULT ValidateServerHandle(const HANDLE handle)
|
||||
{
|
||||
// Make sure this is a console file.
|
||||
FILE_FS_DEVICE_INFORMATION DeviceInformation;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
const auto Status = NtQueryVolumeInformationFile(handle, &IoStatusBlock, &DeviceInformation, sizeof(DeviceInformation), FileFsDeviceInformation);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
RETURN_NTSTATUS(Status);
|
||||
}
|
||||
else if (DeviceInformation.DeviceType != FILE_DEVICE_CONSOLE)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#if TIL_FEATURE_LEGACYCONHOST_ENABLED
|
||||
static bool useV2 = true;
|
||||
static bool ConhostV2ForcedInRegistry()
|
||||
{
|
||||
@@ -122,6 +101,26 @@ static bool ConhostV2ForcedInRegistry()
|
||||
return fShouldUseConhostV2;
|
||||
}
|
||||
|
||||
[[nodiscard]] static HRESULT ValidateServerHandle(const HANDLE handle)
|
||||
{
|
||||
// Make sure this is a console file.
|
||||
FILE_FS_DEVICE_INFORMATION DeviceInformation;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
const auto Status = NtQueryVolumeInformationFile(handle, &IoStatusBlock, &DeviceInformation, sizeof(DeviceInformation), FileFsDeviceInformation);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
RETURN_NTSTATUS(Status);
|
||||
}
|
||||
else if (DeviceInformation.DeviceType != FILE_DEVICE_CONSOLE)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldUseLegacyConhost(const ConsoleArguments& args)
|
||||
{
|
||||
if (args.InConptyMode())
|
||||
@@ -186,7 +185,6 @@ static bool ShouldUseLegacyConhost(const ConsoleArguments& args)
|
||||
|
||||
return hr;
|
||||
}
|
||||
#endif // TIL_FEATURE_LEGACYCONHOST_ENABLED
|
||||
|
||||
// Routine Description:
|
||||
// - Called back when COM says there is nothing left for our server to do and we can tear down.
|
||||
@@ -305,7 +303,6 @@ int CALLBACK wWinMain(
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if TIL_FEATURE_LEGACYCONHOST_ENABLED
|
||||
if (ShouldUseLegacyConhost(args))
|
||||
{
|
||||
useV2 = false;
|
||||
@@ -324,7 +321,6 @@ int CALLBACK wWinMain(
|
||||
}
|
||||
}
|
||||
if (useV2)
|
||||
#endif // TIL_FEATURE_LEGACYCONHOST_ENABLED
|
||||
{
|
||||
if (args.ShouldCreateServerHandle())
|
||||
{
|
||||
|
||||
@@ -80,7 +80,8 @@ namespace DbcsWriteRead
|
||||
const bool fReadUnicode,
|
||||
CharInfoPattern& rgChars);
|
||||
|
||||
void Verify(std::span<CHAR_INFO> rgExpected, std::span<CHAR_INFO> rgActual);
|
||||
void Verify(const CharInfoPattern& rgExpected,
|
||||
const CharInfoPattern& rgActual);
|
||||
|
||||
void PrepExpected(
|
||||
const WORD wAttrWritten,
|
||||
@@ -157,10 +158,6 @@ class DbcsTests
|
||||
BEGIN_TEST_METHOD(TestDbcsBackupRestore)
|
||||
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
|
||||
END_TEST_METHOD()
|
||||
|
||||
BEGIN_TEST_METHOD(TestInvalidTrailer)
|
||||
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
|
||||
END_TEST_METHOD()
|
||||
};
|
||||
|
||||
bool DbcsTests::DbcsTestSetup()
|
||||
@@ -425,7 +422,7 @@ namespace PrepPattern
|
||||
static constexpr WORD leading = COMMON_LVB_LEADING_BYTE;
|
||||
static constexpr WORD trailing = COMMON_LVB_TRAILING_BYTE;
|
||||
|
||||
constexpr void replaceColorPlaceholders(std::span<CHAR_INFO> pattern, WORD attr)
|
||||
constexpr void replaceColorPlaceholders(CharInfoPattern& pattern, WORD attr)
|
||||
{
|
||||
for (auto& info : pattern)
|
||||
{
|
||||
@@ -1320,9 +1317,9 @@ void DbcsWriteRead::RetrieveOutput(const HANDLE hOut,
|
||||
}
|
||||
}
|
||||
|
||||
void DbcsWriteRead::Verify(std::span<CHAR_INFO> rgExpected, std::span<CHAR_INFO> rgActual)
|
||||
void DbcsWriteRead::Verify(const CharInfoPattern& rgExpected,
|
||||
const CharInfoPattern& rgActual)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(rgExpected.size(), rgActual.size());
|
||||
// We will walk through for the number of CHAR_INFOs expected.
|
||||
for (size_t i = 0; i < rgExpected.size(); i++)
|
||||
{
|
||||
@@ -2052,50 +2049,39 @@ void DbcsTests::TestDbcsStdCoutScenario()
|
||||
// In other words, writing a trailing CHAR_INFO will also automatically write a leading CHAR_INFO in the preceding cell.
|
||||
void DbcsTests::TestDbcsBackupRestore()
|
||||
{
|
||||
static_assert(PrepPattern::DoubledW.size() == 16);
|
||||
|
||||
const auto out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
// We backup/restore 2 lines at once to ensure that it works even then. After all, an incorrect implementation
|
||||
// might ignore all but the absolutely first CHAR_INFO instead of handling the first CHAR_INFO *on each row*.
|
||||
std::array<CHAR_INFO, 32> expected;
|
||||
std::ranges::copy(PrepPattern::DoubledW, expected.begin() + 0);
|
||||
std::ranges::copy(PrepPattern::DoubledW, expected.begin() + 16);
|
||||
|
||||
std::array<CHAR_INFO, 16> expected = PrepPattern::DoubledW;
|
||||
PrepPattern::replaceColorPlaceholders(expected, FOREGROUND_BLUE | FOREGROUND_INTENSITY | BACKGROUND_GREEN);
|
||||
|
||||
// DoubledW will show up like this in the top/left corner of the terminal:
|
||||
// +----------------
|
||||
// |QいかなZYXWVUTに
|
||||
// |QいかなZYXWVUTに
|
||||
//
|
||||
// Since those 4 Japanese characters probably aren't going to be monospace for you in your editor
|
||||
// (as they most likely aren't exactly 2 ASCII characters wide), I'll continue referring to them like this:
|
||||
// +----------------
|
||||
// |QaabbccZYXWVUTdd
|
||||
// |QaabbccZYXWVUTdd
|
||||
{
|
||||
SMALL_RECT region{ 0, 0, 15, 1 };
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleOutputW(out, expected.data(), { 16, 2 }, {}, ®ion));
|
||||
SMALL_RECT region{ .Left = 0, .Right = 15 };
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleOutputW(out, expected.data(), { 16, 1 }, {}, ®ion));
|
||||
}
|
||||
|
||||
// Make a "backup" of the viewport. The twist is that our backup region only
|
||||
// copies the trailing/leading half of the first/last glyph respectively like so:
|
||||
// +----------------
|
||||
// | abbccZYXWVUTd
|
||||
std::array<CHAR_INFO, 26> backup{};
|
||||
constexpr COORD backupSize{ 13, 2 };
|
||||
SMALL_RECT backupRegion{ 2, 0, 14, 1 };
|
||||
std::array<CHAR_INFO, 13> backup{};
|
||||
constexpr COORD backupSize{ 13, 1 };
|
||||
SMALL_RECT backupRegion{ .Left = 2, .Right = 14 };
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputW(out, backup.data(), backupSize, {}, &backupRegion));
|
||||
|
||||
// Destroy the text with some narrow ASCII characters, resulting in:
|
||||
// +----------------
|
||||
// |Qxxxxxxxxxxxxxxx
|
||||
// |Qxxxxxxxxxxxxxxx
|
||||
{
|
||||
DWORD ignored;
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(FillConsoleOutputCharacterW(out, L'x', 15, { 1, 0 }, &ignored));
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(FillConsoleOutputCharacterW(out, L'x', 15, { 1, 1 }, &ignored));
|
||||
}
|
||||
|
||||
// Restore our "backup". The trailing half of the first wide glyph (indicated as "a" above)
|
||||
@@ -2103,52 +2089,20 @@ void DbcsTests::TestDbcsBackupRestore()
|
||||
// matching leading/trailing half respectively. In other words, this:
|
||||
// +----------------
|
||||
// | abbccZYXWVUTd
|
||||
// | abbccZYXWVUTd
|
||||
//
|
||||
// turns into this:
|
||||
// +----------------
|
||||
// | aabbccZYXWVUTdd
|
||||
// | aabbccZYXWVUTdd
|
||||
//
|
||||
// and so we restore this, overwriting all the "x" characters in the process:
|
||||
// +----------------
|
||||
// |QいかなZYXWVUTに
|
||||
// |QいかなZYXWVUTに
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleOutputW(out, backup.data(), backupSize, {}, &backupRegion));
|
||||
|
||||
std::array<CHAR_INFO, 32> infos{};
|
||||
std::array<CHAR_INFO, 16> infos{};
|
||||
{
|
||||
SMALL_RECT region{ 0, 0, 15, 1 };
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputW(out, infos.data(), { 16, 2 }, {}, ®ion));
|
||||
SMALL_RECT region{ .Left = 0, .Right = 15 };
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputW(out, infos.data(), { 16, 1 }, {}, ®ion));
|
||||
}
|
||||
DbcsWriteRead::Verify(expected, infos);
|
||||
}
|
||||
|
||||
// As tested by TestDbcsBackupRestore(), we do want to allow users to write trailers into the buffer, to allow
|
||||
// for an area of the buffer to be backed up and restored via Read/WriteConsoleOutput. But apart from that use
|
||||
// case, we'd generally do best to avoid trailers whenever possible, as conhost basically ignored them in the
|
||||
// past and only rendered leaders. Applications might now be relying on us effectively ignoring trailers.
|
||||
void DbcsTests::TestInvalidTrailer()
|
||||
{
|
||||
auto expected = PrepPattern::DoubledW;
|
||||
auto input = expected;
|
||||
decltype(input) output{};
|
||||
|
||||
for (auto& v : input)
|
||||
{
|
||||
if (WI_IsFlagSet(v.Attributes, COMMON_LVB_TRAILING_BYTE))
|
||||
{
|
||||
v.Char.UnicodeChar = 0xfffd;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
static constexpr COORD bufferSize{ 16, 1 };
|
||||
SMALL_RECT region{ 0, 0, 15, 0 };
|
||||
const auto out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleOutputW(out, input.data(), bufferSize, {}, ®ion));
|
||||
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputW(out, output.data(), bufferSize, {}, ®ion));
|
||||
}
|
||||
|
||||
DbcsWriteRead::Verify(expected, output);
|
||||
}
|
||||
|
||||
@@ -17,13 +17,6 @@
|
||||
regular builds, while preventing the build failure during fuzzing builds.
|
||||
-->
|
||||
<ConfigurationType Condition="'$(Configuration)'=='Fuzzing'">StaticLibrary</ConfigurationType>
|
||||
|
||||
<!--
|
||||
OpenConsoleProxy gets copied out of our app package and into a shared system store. As such, it can't take a
|
||||
dependency on any libraries inside our package **or** inside any of our dependency packages. It has to stand
|
||||
on its own.
|
||||
-->
|
||||
<EnableHybridCRT>true</EnableHybridCRT>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)src\common.build.pre.props" />
|
||||
<ItemGroup>
|
||||
@@ -84,6 +77,43 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!--
|
||||
OpenConsoleProxy gets copied out of our app package and into a shared system store. As such, it can't take a
|
||||
dependency on any libraries inside our package **or** inside any of our dependency packages. It has to stand
|
||||
on its own.
|
||||
Therefore, we're going to use the Hybrid CRT model from WinAppSDK for only OpenConsoleProxy. It statically
|
||||
links the runtime and STL and dynamically links the UCRT instead of the VC++ CRT. The UCRT ships with Windows.
|
||||
WinAppSDK asserts that this is "supported according to the CRT maintainer."
|
||||
-->
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
</Project>
|
||||
|
||||
510
src/inc/til/env.h
Normal file
510
src/inc/til/env.h
Normal file
@@ -0,0 +1,510 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wil\token_helpers.h"
|
||||
#include <winternl.h>
|
||||
|
||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
//
|
||||
// A case-insensitive wide-character map is used to store environment variables
|
||||
// due to documented requirements:
|
||||
//
|
||||
// "All strings in the environment block must be sorted alphabetically by name.
|
||||
// The sort is case-insensitive, Unicode order, without regard to locale.
|
||||
// Because the equal sign is a separator, it must not be used in the name of
|
||||
// an environment variable."
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/ProcThread/changing-environment-variables
|
||||
//
|
||||
struct wstring_case_insensitive_compare
|
||||
{
|
||||
[[nodiscard]] bool operator()(const std::wstring& lhs, const std::wstring& rhs) const noexcept
|
||||
{
|
||||
return (::_wcsicmp(lhs.c_str(), rhs.c_str()) < 0);
|
||||
}
|
||||
};
|
||||
|
||||
namespace vars
|
||||
{
|
||||
static constexpr std::wstring_view system_root{ L"SystemRoot" };
|
||||
static constexpr std::wstring_view system_drive{ L"SystemDrive" };
|
||||
static constexpr std::wstring_view all_users_profile{ L"ALLUSERSPROFILE" };
|
||||
static constexpr std::wstring_view public_var{ L"PUBLIC" };
|
||||
static constexpr std::wstring_view program_data{ L"ProgramData" };
|
||||
static constexpr std::wstring_view computer_name{ L"COMPUTERNAME" };
|
||||
static constexpr std::wstring_view user_name{ L"USERNAME" };
|
||||
static constexpr std::wstring_view user_domain{ L"USERDOMAIN" };
|
||||
static constexpr std::wstring_view user_dns_domain{ L"USERDNSDOMAIN" };
|
||||
static constexpr std::wstring_view home_drive{ L"HOMEDRIVE" };
|
||||
static constexpr std::wstring_view home_share{ L"HOMESHARE" };
|
||||
static constexpr std::wstring_view home_path{ L"HOMEPATH" };
|
||||
static constexpr std::wstring_view user_profile{ L"USERPROFILE" };
|
||||
static constexpr std::wstring_view app_data{ L"APPDATA" };
|
||||
static constexpr std::wstring_view local_app_data{ L"LOCALAPPDATA" };
|
||||
|
||||
static constexpr std::wstring_view program_files{ L"ProgramFiles" };
|
||||
static constexpr std::wstring_view program_files_x86{ L"ProgramFiles(x86)" };
|
||||
static constexpr std::wstring_view program_files_arm64{ L"ProgramFiles(Arm)" };
|
||||
static constexpr std::wstring_view program_w6432{ L"ProgramW6432" };
|
||||
static constexpr std::wstring_view common_program_files{ L"CommonProgramFiles" };
|
||||
static constexpr std::wstring_view common_program_files_x86{ L"CommonProgramFiles(x86)" };
|
||||
static constexpr std::wstring_view common_program_files_arm64{ L"CommonProgramFiles(Arm)" };
|
||||
static constexpr std::wstring_view common_program_w6432{ L"CommonProgramW6432" };
|
||||
|
||||
const std::map<std::wstring, std::wstring_view> program_files_map{
|
||||
{ L"ProgramFilesDir", program_files },
|
||||
{ L"CommonFilesDir", common_program_files },
|
||||
#ifdef _WIN64
|
||||
#ifdef _M_ARM64
|
||||
{ L"ProgramFilesDir (Arm)", program_files_arm64 },
|
||||
{ L"CommonFilesDir (Arm)", common_program_files_arm64 },
|
||||
#endif
|
||||
{ L"ProgramFilesDir (x86)", program_files_x86 },
|
||||
{ L"CommonFilesDir (x86)", common_program_files_x86 },
|
||||
{ L"ProgramW6432Dir", program_w6432 },
|
||||
{ L"CommonW6432Dir", common_program_w6432 },
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace reg
|
||||
{
|
||||
static constexpr std::wstring_view program_files_root{ LR"(Software\Microsoft\Windows\CurrentVersion)" };
|
||||
static constexpr std::wstring_view system_env_var_root{ LR"(SYSTEM\CurrentControlSet\Control\Session Manager\Environment)" };
|
||||
static constexpr std::wstring_view user_env_var_root{ LR"(Environment)" };
|
||||
static constexpr std::wstring_view user_volatile_env_var_root{ LR"(Volatile Environment)" };
|
||||
static constexpr std::wstring_view user_volatile_session_env_var_root_pattern{ LR"(Volatile Environment\{0:d})" };
|
||||
};
|
||||
};
|
||||
|
||||
namespace wiltmp
|
||||
{
|
||||
/** Looks up the computer name and fails if it is not found. */
|
||||
template<typename string_type, size_t initialBufferLength = MAX_COMPUTERNAME_LENGTH + 1>
|
||||
inline HRESULT GetComputerNameW(string_type& result) WI_NOEXCEPT
|
||||
{
|
||||
return wil::AdaptFixedSizeToAllocatedResult<string_type, initialBufferLength>(result,
|
||||
[&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT {
|
||||
// If the function succeeds, the return value is the number of characters stored in the buffer
|
||||
// pointed to by lpBuffer, not including the terminating null character.
|
||||
//
|
||||
// If lpBuffer is not large enough to hold the data, the return value is the buffer size, in
|
||||
// characters, required to hold the string and its terminating null character and the contents of
|
||||
// lpBuffer are undefined.
|
||||
//
|
||||
// If the function fails, the return value is zero. If the specified environment variable was not
|
||||
// found in the environment block, GetLastError returns ERROR_ENVVAR_NOT_FOUND.
|
||||
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
|
||||
DWORD length = static_cast<DWORD>(valueLength);
|
||||
|
||||
auto result = ::GetComputerNameW(value, &length);
|
||||
*valueLengthNeededWithNul = length;
|
||||
RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(result);
|
||||
if (*valueLengthNeededWithNul < valueLength)
|
||||
{
|
||||
(*valueLengthNeededWithNul)++; // It fit, account for the null.
|
||||
}
|
||||
return S_OK;
|
||||
});
|
||||
}
|
||||
|
||||
/** Looks up the computer name and returns null if it is not found. */
|
||||
template<typename string_type, size_t initialBufferLength = MAX_COMPUTERNAME_LENGTH + 1>
|
||||
HRESULT TryGetComputerNameW(string_type& result) WI_NOEXCEPT
|
||||
{
|
||||
const auto hr = wiltmp::GetComputerNameW<string_type, initialBufferLength>(result);
|
||||
RETURN_HR_IF(hr, FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND)));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
/** Looks up the computer name and fails if it is not found. */
|
||||
template<typename string_type = wil::unique_cotaskmem_string, size_t initialBufferLength = MAX_COMPUTERNAME_LENGTH + 1>
|
||||
string_type GetComputerNameW()
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED((wiltmp::GetComputerNameW<string_type, initialBufferLength>(result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Looks up the computer name and returns null if it is not found. */
|
||||
template<typename string_type = wil::unique_cotaskmem_string, size_t initialBufferLength = MAX_COMPUTERNAME_LENGTH + 1>
|
||||
string_type TryGetComputerNameW()
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED((wiltmp::TryGetComputerNameW<string_type, initialBufferLength>(result)));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Looks up a registry value from 'key' and fails if it is not found. */
|
||||
template<typename string_type, size_t initialBufferLength = 256>
|
||||
inline HRESULT RegQueryValueExW(HKEY key, PCWSTR valueName, string_type& result) WI_NOEXCEPT
|
||||
{
|
||||
return wil::AdaptFixedSizeToAllocatedResult<string_type, initialBufferLength>(result,
|
||||
[&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT {
|
||||
auto length = gsl::narrow<DWORD>(valueLength * sizeof(wchar_t));
|
||||
const auto status = ::RegQueryValueExW(key, valueName, 0, nullptr, reinterpret_cast<BYTE*>(value), &length);
|
||||
// length will receive the number of bytes including trailing null byte. Convert to a number of wchar_t's.
|
||||
// AdaptFixedSizeToAllocatedResult will then resize buffer to valueLengthNeededWithNull.
|
||||
// We're rounding up to prevent infinite loops if the data isn't a REG_SZ and length isn't divisible by 2.
|
||||
*valueLengthNeededWithNul = (length + sizeof(wchar_t) - 1) / sizeof(wchar_t);
|
||||
return status == ERROR_MORE_DATA ? S_OK : HRESULT_FROM_WIN32(status);
|
||||
});
|
||||
}
|
||||
|
||||
/** Looks up a registry value from 'key' and returns null if it is not found. */
|
||||
template<typename string_type, size_t initialBufferLength = 256>
|
||||
HRESULT TryRegQueryValueExW(HKEY key, PCWSTR valueName, string_type& result) WI_NOEXCEPT
|
||||
{
|
||||
const auto hr = wiltmp::TryRegQueryValueExW<string_type, initialBufferLength>(key, valueName, result);
|
||||
RETURN_HR_IF(hr, FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND)));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
/** Looks up a registry value from 'key' and fails if it is not found. */
|
||||
template<typename string_type = wil::unique_cotaskmem_string, size_t initialBufferLength = 256>
|
||||
string_type RegQueryValueExW(HKEY key, PCWSTR valueName)
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED((wiltmp::RegQueryValueExW<string_type, initialBufferLength>(key, valueName, result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Looks up a registry value from 'key' and returns null if it is not found. */
|
||||
template<typename string_type = wil::unique_cotaskmem_string, size_t initialBufferLength = 256>
|
||||
string_type TryRegQueryValueExW(HKEY key, PCWSTR valueName)
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED((wiltmp::TryRegQueryValueExW<string_type, initialBufferLength>(key, valueName, result)));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//! A strongly typed version of the Win32 API GetShortPathNameW.
|
||||
//! Return a path in an allocated buffer for handling long paths.
|
||||
template<typename string_type, size_t stackBufferLength = 256>
|
||||
HRESULT GetShortPathNameW(PCWSTR file, string_type& path)
|
||||
{
|
||||
const auto hr = wil::AdaptFixedSizeToAllocatedResult<string_type, stackBufferLength>(path,
|
||||
[&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT {
|
||||
// Note that GetShortPathNameW() is not limited to MAX_PATH
|
||||
// but it does take a fixed size buffer.
|
||||
*valueLengthNeededWithNull = ::GetShortPathNameW(file, value, static_cast<DWORD>(valueLength));
|
||||
RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0);
|
||||
WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength));
|
||||
if (*valueLengthNeededWithNull < valueLength)
|
||||
{
|
||||
(*valueLengthNeededWithNull)++; // it fit, account for the null
|
||||
}
|
||||
return S_OK;
|
||||
});
|
||||
return hr;
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
//! A strongly typed version of the Win32 API GetShortPathNameW.
|
||||
//! Return a path in an allocated buffer for handling long paths.
|
||||
template<typename string_type = wil::unique_cotaskmem_string, size_t stackBufferLength = 256>
|
||||
string_type GetShortPathNameW(PCWSTR file)
|
||||
{
|
||||
string_type result;
|
||||
THROW_IF_FAILED((GetShortPathNameW<string_type, stackBufferLength>(file, result)));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
class env : public std::map<std::wstring, std::wstring, til::details::wstring_case_insensitive_compare>
|
||||
{
|
||||
private:
|
||||
#ifdef UNIT_TESTING
|
||||
friend class EnvTests;
|
||||
#endif
|
||||
|
||||
// these wstring_views better be null terminated.
|
||||
void get(std::wstring variable)
|
||||
{
|
||||
if (auto value = wil::TryGetEnvironmentVariableW(variable.c_str()))
|
||||
{
|
||||
save_to_map(variable, value.get());
|
||||
}
|
||||
}
|
||||
|
||||
void get_computer_name()
|
||||
{
|
||||
if (auto value = til::details::wiltmp::TryGetComputerNameW())
|
||||
{
|
||||
save_to_map(std::wstring{ til::details::vars::computer_name }, value.get());
|
||||
}
|
||||
}
|
||||
|
||||
void get_user_name_and_domain()
|
||||
try
|
||||
{
|
||||
auto token = wil::open_current_access_token();
|
||||
auto user = wil::get_token_information<TOKEN_USER>(token.get());
|
||||
|
||||
DWORD accountNameSize = 0, userDomainSize = 0;
|
||||
SID_NAME_USE sidNameUse;
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (LookupAccountSidW(nullptr, user.get()->User.Sid, nullptr, &accountNameSize, nullptr, &userDomainSize, &sidNameUse) || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
std::wstring accountName, userDomain;
|
||||
accountName.resize(accountNameSize);
|
||||
userDomain.resize(userDomainSize);
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (LookupAccountSidW(nullptr, user.get()->User.Sid, accountName.data(), &accountNameSize, userDomain.data(), &userDomainSize, &sidNameUse))
|
||||
{
|
||||
save_to_map(std::wstring{ til::details::vars::user_name }, accountName);
|
||||
save_to_map(std::wstring{ til::details::vars::user_domain }, userDomain);
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
void get_program_files()
|
||||
{
|
||||
wil::unique_hkey key;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, til::details::vars::reg::program_files_root.data(), 0, KEY_READ, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
for (auto& [keyName, varName] : til::details::vars::program_files_map)
|
||||
{
|
||||
auto value = til::details::wiltmp::RegQueryValueExW<std::wstring, 256>(key.get(), keyName.c_str());
|
||||
set_user_environment_var(std::wstring{ varName }, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_vars_from_registry(HKEY rootKey, std::wstring_view subkey)
|
||||
{
|
||||
wil::unique_hkey key;
|
||||
if (RegOpenKeyExW(rootKey, subkey.data(), 0, KEY_READ, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD maxValueNameSize = 0, maxValueDataSize = 0;
|
||||
if (RegQueryInfoKeyW(key.get(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &maxValueNameSize, &maxValueDataSize, nullptr, nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
maxValueNameSize++; // the query does not include the terminating null, but needs that space to enum
|
||||
std::wstring valueName;
|
||||
std::basic_string<BYTE> valueData;
|
||||
valueName.resize(maxValueNameSize);
|
||||
valueData.resize(maxValueDataSize);
|
||||
|
||||
for (DWORD pass = 0; pass < 2; ++pass)
|
||||
{
|
||||
DWORD valueNameSize = maxValueNameSize;
|
||||
DWORD valueDataSize = maxValueDataSize;
|
||||
|
||||
DWORD index = 0;
|
||||
DWORD type = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
DWORD result = RegEnumValueW(key.get(), index, valueName.data(), &valueNameSize, nullptr, &type, valueData.data(), &valueDataSize);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
valueName.resize(valueNameSize);
|
||||
valueData.resize(valueDataSize);
|
||||
|
||||
if (valueNameSize)
|
||||
{
|
||||
std::wstring data;
|
||||
if (pass == 0 && (type == REG_SZ) && valueDataSize >= sizeof(wchar_t))
|
||||
{
|
||||
data = {
|
||||
reinterpret_cast<wchar_t*>(valueData.data()), valueData.size() / sizeof(wchar_t)
|
||||
};
|
||||
}
|
||||
else if (pass == 1 && (type == REG_EXPAND_SZ) && valueDataSize >= sizeof(wchar_t))
|
||||
{
|
||||
data = {
|
||||
reinterpret_cast<wchar_t*>(valueData.data()), valueData.size() / sizeof(wchar_t)
|
||||
};
|
||||
data = expand_environment_strings(data.data());
|
||||
}
|
||||
|
||||
// Because Registry data may or may not be null terminated... check if we've managed
|
||||
// to store an extra null in the wstring by telling it to create itself from pointer and size.
|
||||
// If we did, pull it off.
|
||||
if (!data.empty())
|
||||
{
|
||||
if (data.back() == L'\0')
|
||||
{
|
||||
data = data.substr(0, data.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.empty())
|
||||
{
|
||||
if (is_path_var(valueName))
|
||||
{
|
||||
concat_var(valueName, std::wstring{ data });
|
||||
}
|
||||
else
|
||||
{
|
||||
set_user_environment_var(valueName, std::wstring{ data });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
valueName.resize(maxValueNameSize);
|
||||
valueData.resize(maxValueDataSize);
|
||||
valueNameSize = maxValueNameSize;
|
||||
valueDataSize = maxValueDataSize;
|
||||
index++;
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring expand_environment_strings(std::wstring input)
|
||||
{
|
||||
// TODO: this should be replacing from ourselves, not from the OS
|
||||
return wil::ExpandEnvironmentStringsW<std::wstring, 256>(input.data());
|
||||
}
|
||||
|
||||
void set_user_environment_var(std::wstring var, std::wstring value)
|
||||
{
|
||||
value = expand_environment_strings(value);
|
||||
value = check_for_temp(value);
|
||||
save_to_map(var, value);
|
||||
}
|
||||
|
||||
void concat_var(std::wstring var, std::wstring value)
|
||||
{
|
||||
// I wanted contains() but this isn't C++20... yet.
|
||||
if (find(var) != end())
|
||||
{
|
||||
std::wstring existing = at(var);
|
||||
// If it doesn't already trail with a ;, add one.
|
||||
// Otherwise, just take advantage of the one it has.
|
||||
if (existing.back() != L';')
|
||||
{
|
||||
existing.append(L";");
|
||||
}
|
||||
existing.append(value);
|
||||
save_to_map(var, existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
save_to_map(var, value);
|
||||
}
|
||||
}
|
||||
|
||||
void save_to_map(std::wstring var, std::wstring value)
|
||||
{
|
||||
if (!var.empty() && !value.empty())
|
||||
{
|
||||
insert_or_assign(var, value);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr std::wstring_view temp{ L"temp" };
|
||||
static constexpr std::wstring_view tmp{ L"tmp" };
|
||||
std::wstring check_for_temp(std::wstring_view input)
|
||||
{
|
||||
if (!_wcsicmp(input.data(), temp.data()) ||
|
||||
!_wcsicmp(input.data(), tmp.data()))
|
||||
{
|
||||
return til::details::wiltmp::GetShortPathNameW<std::wstring, 256>(input.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::wstring{ input };
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr std::wstring_view path{ L"Path" };
|
||||
static constexpr std::wstring_view libpath{ L"LibPath" };
|
||||
static constexpr std::wstring_view os2libpath{ L"Os2LibPath" };
|
||||
bool is_path_var(std::wstring_view input)
|
||||
{
|
||||
return !_wcsicmp(input.data(), path.data()) || !_wcsicmp(input.data(), libpath.data()) || !_wcsicmp(input.data(), os2libpath.data());
|
||||
}
|
||||
|
||||
void parse(wchar_t* block)
|
||||
{
|
||||
for (wchar_t const* lastCh{ block }; *lastCh != '\0'; ++lastCh)
|
||||
{
|
||||
// Copy current entry into temporary map.
|
||||
const size_t cchEntry{ ::wcslen(lastCh) };
|
||||
const std::wstring_view entry{ lastCh, cchEntry };
|
||||
|
||||
// Every entry is of the form "name=value\0".
|
||||
const auto pos = entry.find_first_of(L"=", 0, 1);
|
||||
THROW_HR_IF(E_UNEXPECTED, pos == std::wstring::npos);
|
||||
|
||||
std::wstring name{ entry.substr(0, pos) }; // portion before '='
|
||||
std::wstring value{ entry.substr(pos + 1) }; // portion after '='
|
||||
|
||||
// Don't replace entries that already exist.
|
||||
try_emplace(std::move(name), std::move(value));
|
||||
lastCh += cchEntry;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
env()
|
||||
{
|
||||
}
|
||||
|
||||
env(wchar_t* block)
|
||||
{
|
||||
parse(block);
|
||||
}
|
||||
|
||||
void regenerate()
|
||||
{
|
||||
// Generally replicates the behavior of shell32!RegenerateUserEnvironment
|
||||
get(std::wstring{ til::details::vars::system_root });
|
||||
get(std::wstring{ til::details::vars::system_drive });
|
||||
get(std::wstring{ til::details::vars::all_users_profile });
|
||||
get(std::wstring{ til::details::vars::public_var });
|
||||
get(std::wstring{ til::details::vars::program_data });
|
||||
get_computer_name();
|
||||
get_user_name_and_domain();
|
||||
get(std::wstring{ til::details::vars::user_dns_domain });
|
||||
get(std::wstring{ til::details::vars::home_drive });
|
||||
get(std::wstring{ til::details::vars::home_share });
|
||||
get(std::wstring{ til::details::vars::home_path });
|
||||
get(std::wstring{ til::details::vars::user_profile });
|
||||
get(std::wstring{ til::details::vars::app_data });
|
||||
get(std::wstring{ til::details::vars::local_app_data });
|
||||
get_program_files();
|
||||
get_vars_from_registry(HKEY_LOCAL_MACHINE, til::details::vars::reg::system_env_var_root);
|
||||
// not processing autoexec.bat
|
||||
get_vars_from_registry(HKEY_CURRENT_USER, til::details::vars::reg::user_env_var_root);
|
||||
get_vars_from_registry(HKEY_CURRENT_USER, til::details::vars::reg::user_volatile_env_var_root);
|
||||
get_vars_from_registry(HKEY_CURRENT_USER, fmt::format(til::details::vars::reg::user_volatile_session_env_var_root_pattern, NtCurrentTeb()->ProcessEnvironmentBlock->SessionId));
|
||||
}
|
||||
|
||||
std::wstring to_string()
|
||||
{
|
||||
std::wstring result;
|
||||
for (const auto& [name, value] : *this)
|
||||
{
|
||||
result += name;
|
||||
result += L"=";
|
||||
result += value;
|
||||
result.append(L"\0", 1); // Override string's natural propensity to stop at \0
|
||||
}
|
||||
result.append(L"\0", 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: should we be a bunch of goofs and make a "watcher" here that sets up its own
|
||||
// quiet little HWND and message pump watching for the WM_SETTINGCHANGE?
|
||||
};
|
||||
};
|
||||
@@ -24,9 +24,9 @@ namespace til::spsc
|
||||
|
||||
namespace details
|
||||
{
|
||||
inline constexpr size_type position_mask = std::numeric_limits<size_type>::max() >> 2u; // 0b00111....
|
||||
inline constexpr size_type revolution_flag = 1u << (std::numeric_limits<size_type>::digits - 2u); // 0b01000....
|
||||
inline constexpr size_type drop_flag = 1u << (std::numeric_limits<size_type>::digits - 1u); // 0b10000....
|
||||
static constexpr size_type position_mask = std::numeric_limits<size_type>::max() >> 2u; // 0b00111....
|
||||
static constexpr size_type revolution_flag = 1u << (std::numeric_limits<size_type>::digits - 2u); // 0b01000....
|
||||
static constexpr size_type drop_flag = 1u << (std::numeric_limits<size_type>::digits - 1u); // 0b10000....
|
||||
|
||||
struct block_initially_policy
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
inline constexpr uint8_t F_ = 0b10; // stripped in clean_filename
|
||||
inline constexpr uint8_t _P = 0b01; // stripped in clean_path
|
||||
inline constexpr uint8_t FP = 0b11; // stripped in clean_filename and clean_path
|
||||
inline constexpr std::array<uint8_t, 128> pathFilter{ {
|
||||
static constexpr std::array<uint8_t, 128> pathFilter{ {
|
||||
// clang-format off
|
||||
__ /* NUL */, __ /* SOH */, __ /* STX */, __ /* ETX */, __ /* EOT */, __ /* ENQ */, __ /* ACK */, __ /* BEL */, __ /* BS */, __ /* HT */, __ /* LF */, __ /* VT */, __ /* FF */, __ /* CR */, __ /* SO */, __ /* SI */,
|
||||
__ /* DLE */, __ /* DC1 */, __ /* DC2 */, __ /* DC3 */, __ /* DC4 */, __ /* NAK */, __ /* SYN */, __ /* ETB */, __ /* CAN */, __ /* EM */, __ /* SUB */, __ /* ESC */, __ /* FS */, __ /* GS */, __ /* RS */, __ /* US */,
|
||||
|
||||
@@ -213,20 +213,20 @@ try
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultConsoleById(const IID& iid) noexcept
|
||||
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultConsoleById(const IID& iid, const bool useRegExe) noexcept
|
||||
{
|
||||
return s_Set(DELEGATION_CONSOLE_KEY_NAME, iid);
|
||||
return s_Set(DELEGATION_CONSOLE_KEY_NAME, iid, useRegExe);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultTerminalById(const IID& iid) noexcept
|
||||
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultTerminalById(const IID& iid, const bool useRegExe) noexcept
|
||||
{
|
||||
return s_Set(DELEGATION_TERMINAL_KEY_NAME, iid);
|
||||
return s_Set(DELEGATION_TERMINAL_KEY_NAME, iid, useRegExe);
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultByPackage(const DelegationPackage& package) noexcept
|
||||
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultByPackage(const DelegationPackage& package, const bool useRegExe) noexcept
|
||||
{
|
||||
RETURN_IF_FAILED(s_SetDefaultConsoleById(package.pair.console));
|
||||
RETURN_IF_FAILED(s_SetDefaultTerminalById(package.pair.terminal));
|
||||
RETURN_IF_FAILED(s_SetDefaultConsoleById(package.pair.console, useRegExe));
|
||||
RETURN_IF_FAILED(s_SetDefaultTerminalById(package.pair.terminal, useRegExe));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -285,23 +285,64 @@ CATCH_RETURN()
|
||||
return { DelegationPairKind::Custom, values[0], values[1] };
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT DelegationConfig::s_Set(PCWSTR value, const CLSID clsid) noexcept
|
||||
[[nodiscard]] HRESULT DelegationConfig::s_Set(PCWSTR value, const CLSID clsid, const bool useRegExe) noexcept
|
||||
try
|
||||
{
|
||||
wil::unique_hkey currentUserKey;
|
||||
wil::unique_hkey consoleKey;
|
||||
// BODGY
|
||||
// A Centennial application is not allowed to write the system registry and is redirected
|
||||
// to a per-package copy-on-write hive.
|
||||
// The restricted capability "unvirtualizedResources" can be combined with
|
||||
// desktop6:RegistryWriteVirtualization to opt-out... but...
|
||||
// - It will no longer be possible to double-click install through the App Installer
|
||||
// - It requires a special exception to submit to the store
|
||||
// - There MAY be some cleanup logic where the app catalog may try to undo
|
||||
// whatever the package did.
|
||||
// This works around it by shelling out to reg.exe because somehow that's just peachy.
|
||||
if (useRegExe)
|
||||
{
|
||||
wil::unique_cotaskmem_string str;
|
||||
RETURN_IF_FAILED(StringFromCLSID(clsid, &str));
|
||||
|
||||
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_OpenConsoleKey(¤tUserKey, &consoleKey));
|
||||
auto regExePath = wil::ExpandEnvironmentStringsW<std::wstring>(L"%WINDIR%\\System32\\reg.exe");
|
||||
|
||||
// Create method for registry is a "create if not exists, otherwise open" function.
|
||||
wil::unique_hkey startupKey;
|
||||
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_CreateKey(consoleKey.get(), L"%%Startup", &startupKey));
|
||||
auto command = wil::str_printf<std::wstring>(L"%s ADD HKCU\\Console\\%%%%Startup /v %s /t REG_SZ /d %s /f", regExePath.c_str(), value, str.get());
|
||||
|
||||
wil::unique_cotaskmem_string str;
|
||||
RETURN_IF_FAILED(StringFromCLSID(clsid, &str));
|
||||
wil::unique_process_information pi;
|
||||
STARTUPINFOEX siEx{ 0 };
|
||||
siEx.StartupInfo.cb = sizeof(siEx);
|
||||
|
||||
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_SetValue(startupKey.get(), value, REG_SZ, reinterpret_cast<BYTE*>(str.get()), gsl::narrow<DWORD>(wcslen(str.get()) * sizeof(wchar_t))));
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
nullptr,
|
||||
command.data(),
|
||||
nullptr, // lpProcessAttributes
|
||||
nullptr, // lpThreadAttributes
|
||||
false, // bInheritHandles
|
||||
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW, // dwCreationFlags
|
||||
nullptr, // lpEnvironment
|
||||
nullptr,
|
||||
&siEx.StartupInfo, // lpStartupInfo
|
||||
&pi // lpProcessInformation
|
||||
));
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
wil::unique_hkey currentUserKey;
|
||||
wil::unique_hkey consoleKey;
|
||||
|
||||
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_OpenConsoleKey(¤tUserKey, &consoleKey));
|
||||
|
||||
// Create method for registry is a "create if not exists, otherwise open" function.
|
||||
wil::unique_hkey startupKey;
|
||||
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_CreateKey(consoleKey.get(), L"%%Startup", &startupKey));
|
||||
|
||||
wil::unique_cotaskmem_string str;
|
||||
RETURN_IF_FAILED(StringFromCLSID(clsid, &str));
|
||||
|
||||
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_SetValue(startupKey.get(), value, REG_SZ, reinterpret_cast<BYTE*>(str.get()), gsl::narrow<DWORD>(wcslen(str.get()) * sizeof(wchar_t))));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user