Repository: microsoft/terminal (language: cpp)

Issue:
conpty.dll readiness: ship all architectures of OpenConsole, detect the right one.
The pseudoconsole host _must_ match the system architecture, not the application architecture.


Discussion / hints:

Fix patch:
diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt
index ec940e1dbfc..4b755b30e6b 100644
--- a/.github/actions/spelling/excludes.txt
+++ b/.github/actions/spelling/excludes.txt
@@ -52,6 +52,7 @@ SUMS$
 \.xpm$
 \.yml$
 \.zip$
+^build/config/
 ^consolegit2gitfilters\.json$
 ^dep/
 ^doc/reference/master-sequence-list.csv$
diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt
index f196d7ce493..804d81e0c8d 100644
--- a/.github/actions/spelling/expect/expect.txt
+++ b/.github/actions/spelling/expect/expect.txt
@@ -1116,6 +1116,7 @@ Imatch
 ime
 Imm
 IMouse
+IMPEXP
 impl
 inbox
 inclusivity
@@ -2018,6 +2019,7 @@ reparenting
 replatformed
 Replymessage
 repositorypath
+Requiresx
 rescap
 Resequence
 RESETCONTENT
diff --git a/build/config/ESRPSigning_ConPTY.json b/build/config/ESRPSigning_ConPTY.json
new file mode 100644
index 00000000000..d01e9c9eabe
--- /dev/null
+++ b/build/config/ESRPSigning_ConPTY.json
@@ -0,0 +1,51 @@
+{
+    "Version": "1.0.0",
+    "UseMinimatch": false,
+    "SignBatches": [
+        {
+            "MatchedPath": [
+                "conpty.dll",
+                "OpenConsole.exe"
+            ],
+            "SigningInfo": {
+                "Operations": [
+                    {
+                        "KeyCode": "CP-230012",
+                        "OperationSetCode": "SigntoolSign",
+                        "Parameters": [
+                            {
+                                "parameterName": "OpusName",
+                                "parameterValue": "Microsoft"
+                            },
+                            {
+                                "parameterName": "OpusInfo",
+                                "parameterValue": "http://www.microsoft.com"
+                            },
+                            {
+                                "parameterName": "FileDigest",
+                                "parameterValue": "/fd \"SHA256\""
+                            },
+                            {
+                                "parameterName": "PageHash",
+                                "parameterValue": "/NPH"
+                            },
+                            {
+                                "parameterName": "TimeStamp",
+                                "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
+                            }
+                        ],
+                        "ToolName": "sign",
+                        "ToolVersion": "1.0"
+                    },
+                    {
+                        "KeyCode": "CP-230012",
+                        "OperationSetCode": "SigntoolVerify",
+                        "Parameters": [],
+                        "ToolName": "sign",
+                        "ToolVersion": "1.0"
+                    }
+                ]
+            }
+        }
+    ]
+}
diff --git a/build/pipelines/release.yml b/build/pipelines/release.yml
index d4c65950474..c78a75978a2 100644
--- a/build/pipelines/release.yml
+++ b/build/pipelines/release.yml
@@ -30,6 +30,10 @@ parameters:
     displayName: "Build Windows Terminal VPack"
     type: boolean
     default: false
+  - name: buildConPTY
+    displayName: "Build ConPTY NuGet"
+    type: boolean
+    default: false
   - name: buildWPF
     displayName: "Build Terminal WPF Control"
     type: boolean
@@ -75,6 +79,13 @@ variables:
       NoNuGetPackBetaVersion: true
     ${{ else }}:
       NuGetPackBetaVersion: preview
+  # 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:
@@ -208,6 +219,15 @@ jobs:
         msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /p:WindowsTerminalReleaseBuild=true /t:Terminal\wpf\PublicTerminalCore
         platform: $(BuildPlatform)
         configuration: $(BuildConfiguration)
+  - ${{ if eq(parameters.buildConPTY, true) }}:
+    - task: VSBuild@1
+      displayName: Build solution **\OpenConsole.sln for ConPTY
+      inputs:
+        solution: '**\OpenConsole.sln'
+        vsVersion: 16.0
+        msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /p:WindowsTerminalReleaseBuild=true /t:Conhost\Host_EXE;Conhost\winconpty_DLL
+        platform: $(BuildPlatform)
+        configuration: $(BuildConfiguration)
   - task: PowerShell@2
     displayName: Source Index PDBs
     inputs:
@@ -252,6 +272,24 @@ jobs:
       inputs:
         PathtoPublish: $(Build.ArtifactStagingDirectory)/appx
         ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
+  - ${{ if eq(parameters.buildConPTY, true) }}:
+    - task: CopyFiles@2
+      displayName: Copy ConPTY to Artifacts
+      inputs:
+        Contents: |-
+          $(Build.SourcesDirectory)/bin/**/conpty.dll
+          $(Build.SourcesDirectory)/bin/**/conpty.lib
+          $(Build.SourcesDirectory)/bin/**/conpty.pdb
+          $(Build.SourcesDirectory)/bin/**/OpenConsole.exe
+          $(Build.SourcesDirectory)/bin/**/OpenConsole.pdb
+        TargetFolder: $(Build.ArtifactStagingDirectory)/conpty
+        OverWrite: true
+        flattenFolders: true
+    - task: PublishBuildArtifacts@1
+      displayName: Publish Artifact (ConPTY)
+      inputs:
+        PathtoPublish: $(Build.ArtifactStagingDirectory)/conpty
+        ArtifactName: conpty-dll-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
   - ${{ if eq(parameters.buildWPF, true) }}:
     - task: CopyFiles@2
       displayName: Copy PublicTerminalCore.dll to Artifacts
@@ -358,6 +396,97 @@ jobs:
         PathtoPublish: $(System.ArtifactsDirectory)
         ArtifactName: appxbundle-signed-$(TerminalTargetWindowsVersion)
 
+- ${{ if eq(parameters.buildConPTY, true) }}:
+  - job: PackageAndSignConPTY
+    strategy:
+      matrix:
+        ${{ each config in parameters.buildConfigurations }}:
+          ${{ config }}:
+            BuildConfiguration: ${{ config }}
+    displayName: Create NuGet Package (ConPTY)
+    dependsOn: Build
+    steps:
+    - checkout: self
+      clean: true
+      fetchDepth: 1
+      submodules: true
+      persistCredentials: True
+    - task: PkgESSetupBuild@12
+      displayName: Package ES - Setup Build
+      inputs:
+        disableOutputRedirect: true
+    - ${{ each platform in parameters.buildPlatforms }}:
+      - task: DownloadBuildArtifacts@0
+        displayName: Download ${{ platform }} ConPTY binaries
+        inputs:
+          artifactName: conpty-dll-${{ platform }}-$(BuildConfiguration)-$(TerminalBestVersionForNuGetPackages)
+          downloadPath: bin\${{ platform }}\$(BuildConfiguration)\
+          extractTars: false
+    - task: PowerShell@2
+      displayName: Move downloaded artifacts around
+      inputs:
+        targetType: inline
+        # Find all artifact files and move them up a directory. Ugh.
+        script: |-
+          Get-ChildItem bin -Recurse -Directory -Filter conpty-dll-* | % {
+            $_ | Get-ChildItem -Recurse -File | % {
+              Move-Item -Verbose $_.FullName $_.Directory.Parent.FullName
+            }
+          }
+          Move-Item bin\x86 bin\Win32
+
+    - task: EsrpCodeSigning@1
+      displayName: Submit ConPTY libraries and OpenConsole for code signing
+      inputs:
+        ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
+        FolderPath: '$(Build.SourcesDirectory)/bin'
+        signType: batchSigning
+        batchSignPolicyFile: '$(Build.SourcesDirectory)\build\config\ESRPSigning_ConPTY.json'
+
+    - task: NuGetToolInstaller@1
+      displayName: Use NuGet 5.10.0
+      inputs:
+        versionSpec: 5.10.0
+    - task: NuGetCommand@2
+      displayName: NuGet pack
+      inputs:
+        command: pack
+        packagesToPack: $(Build.SourcesDirectory)\src\winconpty\package\winconpty.nuspec
+        packDestination: '$(Build.ArtifactStagingDirectory)/nupkg'
+        versioningScheme: byEnvVar
+        versionEnvVar: XES_PACKAGEVERSIONNUMBER
+    - task: EsrpCodeSigning@1
+      displayName: Submit *.nupkg to ESRP for code signing
+      inputs:
+        ConnectedServiceName: 9d6d2960-0793-4d59-943e-78dcb434840a
+        FolderPath: $(Build.ArtifactStagingDirectory)/nupkg
+        Pattern: '*.nupkg'
+        UseMinimatch: true
+        signConfigType: inlineSignParams
+        inlineOperation: >-
+          [
+              {
+                  "KeyCode": "CP-401405",
+                  "OperationCode": "NuGetSign",
+                  "Parameters": {},
+                  "ToolName": "sign",
+                  "ToolVersion": "1.0"
+              },
+              {
+                  "KeyCode": "CP-401405",
+                  "OperationCode": "NuGetVerify",
+                  "Parameters": {},
+                  "ToolName": "sign",
+                  "ToolVersion": "1.0"
+              }
+          ]
+    - task: PublishBuildArtifacts@1
+      displayName: Publish Artifact (nupkg)
+      inputs:
+        PathtoPublish: $(Build.ArtifactStagingDirectory)\nupkg
+        ArtifactName: conpty-nupkg-$(BuildConfiguration)
+
+
 - ${{ if eq(parameters.buildWPF, true) }}:
   - job: PackageAndSignWPF
     strategy:
@@ -381,7 +510,7 @@ jobs:
       - task: DownloadBuildArtifacts@0
         displayName: Download ${{ platform }} PublicTerminalCore
         inputs:
-          artifactName: wpf-dll-${{ platform }}-$(BuildConfiguration)-Win10
+          artifactName: wpf-dll-${{ platform }}-$(BuildConfiguration)-$(TerminalBestVersionForNuGetPackages)
           itemPattern: '**/*.dll'
           downloadPath: bin\${{ platform }}\$(BuildConfiguration)\
           extractTars: false
diff --git a/src/cascadia/TerminalConnection/TerminalConnection.vcxproj b/src/cascadia/TerminalConnection/TerminalConnection.vcxproj
index 0fed7d60aa1..ce6a067c0e9 100644
--- a/src/cascadia/TerminalConnection/TerminalConnection.vcxproj
+++ b/src/cascadia/TerminalConnection/TerminalConnection.vcxproj
@@ -87,6 +87,8 @@
   <Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
   <ItemDefinitionGroup>
     <ClCompile>
+      <!-- By defining this here, we ensure that we don't try to dllimport conpty -->
+      <PreprocessorDefinitions>CONPTY_IMPEXP=;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(IntDir)..\OpenConsoleProxy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
diff --git a/src/host/ft_host/Host.FeatureTests.vcxproj b/src/host/ft_host/Host.FeatureTests.vcxproj
index 6f782a5404e..507dcfab0b4 100644
--- a/src/host/ft_host/Host.FeatureTests.vcxproj
+++ b/src/host/ft_host/Host.FeatureTests.vcxproj
@@ -55,6 +55,8 @@
   </ItemGroup>
   <ItemDefinitionGroup>
     <ClCompile>
+      <!-- By defining this here, we ensure that we don't try to dllimport conpty -->
+      <PreprocessorDefinitions>CONPTY_IMPEXP=;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
   </ItemDefinitionGroup>
diff --git a/src/inc/conpty-static.h b/src/inc/conpty-static.h
index a23d971615b..82982864dd6 100644
--- a/src/inc/conpty-static.h
+++ b/src/inc/conpty-static.h
@@ -11,28 +11,34 @@
 
 #include <consoleapi.h>
 
+#ifndef CONPTY_IMPEXP
+#define CONPTY_IMPEXP __declspec(dllimport)
+#endif
+
+#ifndef CONPTY_EXPORT
 #ifdef __cplusplus
-extern "C" {
+#define CONPTY_EXPORT extern "C" CONPTY_IMPEXP
+#else
+#define CONPTY_EXPORT extern CONPTY_IMPEXP
+#endif
 #endif
 
 #define PSEUDOCONSOLE_RESIZE_QUIRK (2u)
 #define PSEUDOCONSOLE_WIN32_INPUT_MODE (4u)
 #define PSEUDOCONSOLE_PASSTHROUGH_MODE (8u)
 
-HRESULT WINAPI ConptyCreatePseudoConsole(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
+CONPTY_EXPORT HRESULT WINAPI ConptyCreatePseudoConsole(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
 
-HRESULT WINAPI ConptyResizePseudoConsole(HPCON hPC, COORD size);
+CONPTY_EXPORT HRESULT WINAPI ConptyCreatePseudoConsoleAsUser(HANDLE hToken, COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
 
-HRESULT WINAPI ConptyClearPseudoConsole(HPCON hPC);
+CONPTY_EXPORT HRESULT WINAPI ConptyResizePseudoConsole(HPCON hPC, COORD size);
 
-HRESULT WINAPI ConptyShowHidePseudoConsole(HPCON hPC, bool show);
+CONPTY_EXPORT HRESULT WINAPI ConptyClearPseudoConsole(HPCON hPC);
 
-HRESULT WINAPI ConptyReparentPseudoConsole(HPCON hPC, HWND newParent);
+CONPTY_EXPORT HRESULT WINAPI ConptyShowHidePseudoConsole(HPCON hPC, bool show);
 
-VOID WINAPI ConptyClosePseudoConsole(HPCON hPC);
+CONPTY_EXPORT HRESULT WINAPI ConptyReparentPseudoConsole(HPCON hPC, HWND newParent);
 
-HRESULT WINAPI ConptyPackPseudoConsole(HANDLE hServerProcess, HANDLE hRef, HANDLE hSignal, HPCON* phPC);
+CONPTY_EXPORT VOID WINAPI ConptyClosePseudoConsole(HPCON hPC);
 
-#ifdef __cplusplus
-}
-#endif
+CONPTY_EXPORT HRESULT WINAPI ConptyPackPseudoConsole(HANDLE hServerProcess, HANDLE hRef, HANDLE hSignal, HPCON* phPC);
diff --git a/src/winconpty/dll/winconpty.def b/src/winconpty/dll/winconpty.def
index da8a5653533..1a1952bf421 100644
--- a/src/winconpty/dll/winconpty.def
+++ b/src/winconpty/dll/winconpty.def
@@ -1,4 +1,17 @@
 EXPORTS
+    ; Plain old normal aliases
+    ConptyCreatePseudoConsole
+    ConptyCreatePseudoConsoleAsUser
+    ConptyResizePseudoConsole
+    ConptyClosePseudoConsole
+    ConptyClearPseudoConsole
+    ConptyShowHidePseudoConsole
+    ConptyReparentPseudoConsole
+    ConptyPackPseudoConsole
+
+    ; Compatibility aliases for P/Invoke; only required for compatibility
+    ; with the ConPTY surface exported from kernel32.
+    ; New consumers are expected to use the Conpty* versions
     CreatePseudoConsole = ConptyCreatePseudoConsole
     ResizePseudoConsole = ConptyResizePseudoConsole
     ClosePseudoConsole = ConptyClosePseudoConsole
diff --git a/src/winconpty/package/managed/Microsoft.Windows.Console.ConPTY.props b/src/winconpty/package/managed/Microsoft.Windows.Console.ConPTY.props
new file mode 100644
index 00000000000..2aa5b62015d
--- /dev/null
+++ b/src/winconpty/package/managed/Microsoft.Windows.Console.ConPTY.props
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <!-- C# uses normalizes PlatformTarget, whereas C++ does not normalize Platform -->
+    <ConptyNativePlatform Condition="'$(ConptyNativePlatform)'==''">$(PlatformTarget)</ConptyNativePlatform>
+    <ConptyNativePlatform Condition="'$(ConptyNativePlatform)'==''">$(Platform)</ConptyNativePlatform>
+    <ConptyNativePlatform Condition="'$(ConptyNativePlatform)'=='Win32'">x86</ConptyNativePlatform>
+
+    <!-- x86 can run on x64 and ARM64, so needs to ship all three OpenConsoles. -->
+    <ConptyRequiresx86Host   Condition="'$(ConptyNativePlatform)' == 'x86'">true</ConptyRequiresx86Host>
+    <ConptyRequiresx64Host   Condition="'$(ConptyNativePlatform)' == 'x86'">true</ConptyRequiresx64Host>
+    <ConptyRequiresARM64Host Condition="'$(ConptyNativePlatform)' == 'x86'">true</ConptyRequiresARM64Host>
+
+    <!-- x64 can only run on x64 and ARM64, so needs to ship only two OpenConsoles. -->
+    <!-- ConptyRequiresx86Host not set -->
+    <ConptyRequiresx64Host   Condition="'$(ConptyNativePlatform)' == 'x64'">true</ConptyRequiresx64Host>
+    <ConptyRequiresARM64Host Condition="'$(ConptyNativePlatform)' == 'x64'">true</ConptyRequiresARM64Host>
+
+    <!-- ARM64 can only run on ARM64, so only needs to ship the final OpenConsole. -->
+    <!-- ConptyRequiresx86Host not set -->
+    <!-- ConptyRequiresx64Host not set -->
+    <ConptyRequiresARM64Host Condition="'$(ConptyNativePlatform)' == 'ARM64'">true</ConptyRequiresARM64Host>
+  </PropertyGroup>
+</Project>
diff --git a/src/winconpty/package/managed/Microsoft.Windows.Console.ConPTY.targets b/src/winconpty/package/managed/Microsoft.Windows.Console.ConPTY.targets
new file mode 100644
index 00000000000..325cf10a5b8
--- /dev/null
+++ b/src/winconpty/package/managed/Microsoft.Windows.Console.ConPTY.targets
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <None Condition="'$(ConptyRequiresx86Host)'=='true'" Include="$(MSBuildThisFileDirectory)\native\runtimes\x86\OpenConsole.exe">
+      <Link>x86\OpenConsole.exe</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
+    </None>
+    <None Condition="'$(ConptyRequiresx64Host)'=='true'" Include="$(MSBuildThisFileDirectory)\native\runtimes\x64\OpenConsole.exe">
+      <Link>x64\OpenConsole.exe</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
+    </None>
+    <None Condition="'$(ConptyRequiresARM64Host)'=='true'" Include="$(MSBuildThisFileDirectory)\native\runtimes\arm64\OpenConsole.exe">
+      <Link>arm64\OpenConsole.exe</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
+    </None>
+  </ItemGroup>
+</Project>
diff --git a/src/winconpty/package/native/Microsoft.Windows.Console.ConPTY.props b/src/winconpty/package/native/Microsoft.Windows.Console.ConPTY.props
new file mode 100644
index 00000000000..879cbb4ddde
--- /dev/null
+++ b/src/winconpty/package/native/Microsoft.Windows.Console.ConPTY.props
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildThisProjectDirectory)\..\Microsoft.Windows.Console.ConPTY.props" />
+</Project>
diff --git a/src/winconpty/package/native/Microsoft.Windows.Console.ConPTY.targets b/src/winconpty/package/native/Microsoft.Windows.Console.ConPTY.targets
new file mode 100644
index 00000000000..00a7a31065b
--- /dev/null
+++ b/src/winconpty/package/native/Microsoft.Windows.Console.ConPTY.targets
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)..\..\inc\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(ConptyNativePlatform)\lib\uap10.0\conpty.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(ConptyNativePlatform)\native\conpty.dll" />
+    <ReferenceCopyLocalPaths Condition="'$(ConptyRequiresx86Host)'=='true'" Include="$(MSBuildThisFileDirectory)\runtimes\x86\OpenConsole.exe">
+      <DestinationSubDirectory>x86\</DestinationSubDirectory>
+    </ReferenceCopyLocalPaths>
+    <ReferenceCopyLocalPaths Condition="'$(ConptyRequiresx64Host)'=='true'" Include="$(MSBuildThisFileDirectory)\runtimes\x64\OpenConsole.exe">
+      <DestinationSubDirectory>x64\</DestinationSubDirectory>
+    </ReferenceCopyLocalPaths>
+    <ReferenceCopyLocalPaths Condition="'$(ConptyRequiresARM64Host)'=='true'" Include="$(MSBuildThisFileDirectory)\runtimes\arm64\OpenConsole.exe">
+      <DestinationSubDirectory>arm64\</DestinationSubDirectory>
+    </ReferenceCopyLocalPaths>
+  </ItemGroup>
+</Project>
diff --git a/src/winconpty/package/winconpty.nuspec b/src/winconpty/package/winconpty.nuspec
new file mode 100644
index 00000000000..ba34b1511fa
--- /dev/null
+++ b/src/winconpty/package/winconpty.nuspec
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package>
+  <metadata>
+    <id>Microsoft.Windows.Console.ConPTY</id>
+    <version>0.0.1</version>
+    <authors>Microsoft</authors>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <license type="expression">MIT</license>
+    <projectUrl>https://github.com/microsoft/terminal</projectUrl>
+    <description>This package allows applications to host Windows Console sessions. It should work on all versions of Windows 10.0.17763.0 and above.</description>
+    <copyright>© Microsoft Corporation</copyright>
+    <dependencies />
+  </metadata>
+  <files>
+    <file src="managed/Microsoft.Windows.Console.ConPTY.props" target="build" />
+    <file src="managed/Microsoft.Windows.Console.ConPTY.targets" target="build" />
+    <file src="native/Microsoft.Windows.Console.ConPTY.props" target="build/native" />
+    <file src="native/Microsoft.Windows.Console.ConPTY.targets" target="build/native" />
+
+    <file src="../../../src/inc/conpty-static.h" target="inc/conpty.h" />
+
+    <file src="../../../bin/Win32/Release/conpty.dll" target="runtimes/win10-x86/native" />
+    <file src="../../../bin/Win32/Release/conpty.lib" target="runtimes/win10-x86/lib/uap10.0" />
+    <file src="../../../bin/Win32/Release/OpenConsole.exe" target="build/native/runtimes/x86" />
+
+    <file src="../../../bin/x64/Release/conpty.dll" target="runtimes/win10-x64/native" />
+    <file src="../../../bin/x64/Release/conpty.lib" target="runtimes/win10-x64/lib/uap10.0" />
+    <file src="../../../bin/x64/Release/OpenConsole.exe" target="build/native/runtimes/x64" />
+
+    <file src="../../../bin/ARM64/Release/conpty.lib" target="runtimes/win10-arm64/lib/uap10.0" />
+    <file src="../../../bin/ARM64/Release/conpty.dll" target="runtimes/win10-arm64/native" />
+    <file src="../../../bin/ARM64/Release/OpenConsole.exe" target="build/native/runtimes/arm64" />
+  </files>
+</package>
diff --git a/src/winconpty/winconpty.cpp b/src/winconpty/winconpty.cpp
index f2db69c1652..19b91b797b3 100644
--- a/src/winconpty/winconpty.cpp
+++ b/src/winconpty/winconpty.cpp
@@ -48,6 +48,37 @@ static wchar_t* _ConsoleHostPath()
         modulePath.replace_filename(L"OpenConsole.exe");
         if (!std::filesystem::exists(modulePath))
         {
+            std::wstring_view architectureInfix{};
+            USHORT unusedImageFileMachine{}, nativeMachine{};
+            if (IsWow64Process2(GetCurrentProcess(), &unusedImageFileMachine, &nativeMachine))
+            {
+                // Despite being a machine type, the values IsWow64Process2 returns are *image* types
+                switch (nativeMachine)
+                {
+                case IMAGE_FILE_MACHINE_AMD64:
+                    architectureInfix = L"x64";
+                    break;
+                case IMAGE_FILE_MACHINE_ARM64:
+                    architectureInfix = L"arm64";
+                    break;
+                case IMAGE_FILE_MACHINE_I386:
+                    architectureInfix = L"x86";
+                    break;
+                default:
+                    break;
+                }
+            }
+            if (architectureInfix.empty())
+            {
+                // WHAT?
+                return _InboxConsoleHostPath();
+            }
+            modulePath.replace_filename(architectureInfix);
+            modulePath.append(L"OpenConsole.exe");
+        }
+        if (!std::filesystem::exists(modulePath))
+        {
+            // We tried the architecture infix version and failed, fall back to conhost.
             return _InboxConsoleHostPath();
         }
         auto modulePathAsString{ modulePath.wstring() };


Test patch: