Merged PR 5677497: [Git2Git] Merged PR 5655213: Allow conhost to handoff to registered default app handler

Contains:
- Delegation Configurator that can lookup/edit/save configuration information to registry
- Conhost can lookup the CLSID of a registered default
- Conhost has the ability to handoff a starting visible-window interactive session to the registered default
- Velocity key since this is a big deal and we want to be careful
- IDL for the interface

Related work items: MSFT-16458099
Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev 0ca55027d8180fbbaa145f2fe7a15005856c0f7c
This commit is contained in:
Dustin Howett 2021-02-11 21:07:50 +00:00
parent 38da2ff185
commit 3822d5b662
25 changed files with 560 additions and 114 deletions

View File

@ -364,6 +364,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_Remoting", "src\c
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wpf", "wpf", "{4DAF0299-495E-4CD1-A982-9BAC16A45932}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Proxy", "src\host\proxy\Host.Proxy.vcxproj", "{E437B604-3E98-4F40-A927-E173E818EA4B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
AuditMode|Any CPU = AuditMode|Any CPU
@ -2558,6 +2560,36 @@ Global
{68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|x64.Build.0 = Release|x64
{68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|x86.ActiveCfg = Release|Win32
{68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|x86.Build.0 = Release|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|x64.ActiveCfg = AuditMode|x64
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|x64.Build.0 = AuditMode|x64
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|x86.ActiveCfg = AuditMode|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.AuditMode|x86.Build.0 = AuditMode|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|Any CPU.ActiveCfg = Debug|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|ARM.ActiveCfg = Debug|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|ARM64.Build.0 = Debug|ARM64
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|x64.ActiveCfg = Debug|x64
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|x64.Build.0 = Debug|x64
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|x86.ActiveCfg = Debug|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Debug|x86.Build.0 = Debug|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|Any CPU.ActiveCfg = Release|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|ARM.ActiveCfg = Release|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|ARM64.ActiveCfg = Release|ARM64
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|ARM64.Build.0 = Release|ARM64
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|x64.ActiveCfg = Release|x64
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|x64.Build.0 = Release|x64
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|x86.ActiveCfg = Release|Win32
{E437B604-3E98-4F40-A927-E173E818EA4B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2648,6 +2680,7 @@ Global
{27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {59840756-302F-44DF-AA47-441A9D673202}
{68A10CD3-AA64-465B-AF5F-ED4E9700543C} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{4DAF0299-495E-4CD1-A982-9BAC16A45932} = {59840756-302F-44DF-AA47-441A9D673202}
{E437B604-3E98-4F40-A927-E173E818EA4B} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}

View File

@ -1,4 +1,5 @@
DIRS=exe \
DIRS=proxy \
exe \
lib \
ut_lib \
ut_host \

View File

@ -1,81 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{E437B604-3E98-4F40-A927-E173E818EA4B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>host</RootNamespace>
<ProjectName>Host.DLL</ProjectName>
<TargetName>ConhostV2</TargetName>
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<Import Project="$(SolutionDir)src\common.build.pre.props" />
<ItemGroup>
<ClCompile Include="..\main.cpp" />
<ClCompile Include="..\precomp.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\precomp.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\interactivity\base\lib\InteractivityBase.vcxproj">
<Project>{06ec74cb-9a12-429c-b551-8562ec964846}</Project>
</ProjectReference>
<ProjectReference Include="..\..\interactivity\win32\lib\win32.LIB.vcxproj">
<Project>{06ec74cb-9a12-429c-b551-8532ec964726}</Project>
</ProjectReference>
<ProjectReference Include="..\..\propslib\propslib.vcxproj">
<Project>{345fd5a4-b32b-4f29-bd1c-b033bd2c35cc}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\base\lib\base.vcxproj">
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\gdi\lib\gdi.vcxproj">
<Project>{1c959542-bac2-4e55-9a6d-13251914cbb9}</Project>
</ProjectReference>
<ProjectReference Include="..\..\server\lib\server.vcxproj">
<Project>{18d09a24-8240-42d6-8cb6-236eee820262}</Project>
</ProjectReference>
<ProjectReference Include="..\..\terminal\adapter\lib\adapter.vcxproj">
<Project>{dcf55140-ef6a-4736-a403-957e4f7430bb}</Project>
</ProjectReference>
<ProjectReference Include="..\..\terminal\parser\lib\parser.vcxproj">
<Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project>
</ProjectReference>
<ProjectReference Include="..\..\tsf\tsf.vcxproj">
<Project>{2fd12fbb-1ddb-46d8-b818-1023c624caca}</Project>
</ProjectReference>
<ProjectReference Include="..\..\types\lib\types.vcxproj">
<Project>{18d09a24-8240-42d6-8cb6-236eee820263}</Project>
</ProjectReference>
<ProjectReference Include="..\lib\hostlib.vcxproj">
<Project>{06ec74cb-9a12-429c-b551-8562ec954746}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="ConhostV2.def" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Host.DLL.rc" />
</ItemGroup>
<PropertyGroup>
<EmbedManifest>
</EmbedManifest>
<GenerateManifest>true</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<ModuleDefinitionFile>ConhostV2.def</ModuleDefinitionFile>
<AllowIsolation>true</AllowIsolation>
<AdditionalManifestDependencies>type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'</AdditionalManifestDependencies>
</Link>
</ItemDefinitionGroup>
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
<Import Project="$(SolutionDir)src\common.build.post.props" />
</Project>

View File

@ -70,6 +70,10 @@ public:
ApiRoutines api;
bool handoffTarget = false;
std::optional<CLSID> handoffConsoleClsid;
#ifdef UNIT_TESTING
void EnableConptyModeForTests(std::unique_ptr<Microsoft::Console::Render::VtEngine> vtRenderEngine);
#endif

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{E437B604-3E98-4F40-A927-E173E818EA4B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>openconsoleproxy</RootNamespace>
<ProjectName>OpenConsoleProxy</ProjectName>
<TargetName>OpenConsoleProxy</TargetName>
<ConfigurationType>Utility</ConfigurationType>
</PropertyGroup>
<Import Project="$(SolutionDir)src\common.build.pre.props" />
<ItemGroup>
<ClInclude Include="$(IntDir)\IConsoleHandoff.h" />
</ItemGroup>
<ItemGroup>
<Midl Include="IConsoleHandoff.idl">
<!--
In Razzle, IDL files generate %FileName%.h
In Visual Studio, IDL files generate %FileName%_h.h
Visual Studio is easier to override than Razzle.
This has to be built in both the OS and outside, so we
override the easier-to-override side to a uniform name.
-->
<HeaderFileName>IConsoleHandoff.h</HeaderFileName>
<MinimumTargetSystem>NT100</MinimumTargetSystem>
<OutputDirectory>$(IntDir)</OutputDirectory>
</Midl>
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemDefinitionGroup>
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
<Import Project="$(SolutionDir)src\common.build.post.props" />
</Project>

View File

@ -15,29 +15,16 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\precomp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\precomp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<ClInclude Include="IConsoleHandoff_h.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="ConhostV2.def">
<Midl Include="IConsoleHandoff.idl">
<Filter>Source Files</Filter>
</None>
</Midl>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Host.DLL.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
</Project>

View File

@ -0,0 +1,26 @@
import "oaidl.idl";
import "ocidl.idl";
typedef struct _CONSOLE_PORTABLE_ATTACH_MSG
{
DWORD IdLowPart;
LONG IdHighPart;
ULONG64 Process;
ULONG64 Object;
ULONG Function;
ULONG InputSize;
ULONG OutputSize;
} CONSOLE_PORTABLE_ATTACH_MSG;
typedef CONSOLE_PORTABLE_ATTACH_MSG* PCONSOLE_PORTABLE_ATTACH_MSG;
typedef const CONSOLE_PORTABLE_ATTACH_MSG* PCCONSOLE_PORTABLE_ATTACH_MSG;
[
object,
uuid(2B607BC1-43EB-40C3-95AE-2856ADDB7F23)
] interface IConsoleHandoff : IUnknown
{
HRESULT EstablishHandoff([in, system_handle(sh_file)] HANDLE server,
[in, system_handle(sh_event)] HANDLE inputEvent,
[in, ref] PCCONSOLE_PORTABLE_ATTACH_MSG msg);
};

31
src/host/proxy/sources Normal file
View File

@ -0,0 +1,31 @@
# -------------------------------------
# Windows Console
# - Console Host COM Proxy
# -------------------------------------
# This program provides the COM call and proxy
# information for handing off one console session to another
# capable console host application.
# -------------------------------------
# Program Information
# -------------------------------------
TARGETNAME =
TARGETTYPE = NOTARGET
# -------------------------------------
# Build System Settings
# -------------------------------------
MIDL_FLAGS = $(MIDL_FLAGS)
# -------------------------------------
# Sources, Headers, and Libraries
# -------------------------------------
SOURCES = \
IConsoleHandoff.idl \
INCLUDES = \
$(INCLUDES); \

View File

@ -0,0 +1,6 @@
PUBLIC_PASS0_CONSUMES= \
minkernel\published\base|PASS0 \
onecore\com\published\idlole\publish|PASS0 \
onecore\enduser\sql\xml\msxml3\publish|PASS0 \
onecore\inetcore\published\sdk\inc|PASS0 \

View File

@ -23,6 +23,9 @@
#include "renderData.hpp"
#include "../renderer/base/renderer.hpp"
#include "../inc/conint.h"
#include "../propslib/DelegationConfig.hpp"
#pragma hdrstop
using namespace Microsoft::Console::Interactivity;
@ -32,27 +35,37 @@ const UINT CONSOLE_EVENT_FAILURE_ID = 21790;
const UINT CONSOLE_LPC_PORT_FAILURE_ID = 21791;
[[nodiscard]] HRESULT ConsoleServerInitialization(_In_ HANDLE Server, const ConsoleArguments* const args)
try
{
Globals& Globals = ServiceLocator::LocateGlobals();
try
Globals.pDeviceComm = new ConDrvDeviceComm(Server);
Globals.launchArgs = *args;
Globals.uiOEMCP = GetOEMCP();
Globals.uiWindowsCP = GetACP();
Globals.pFontDefaultList = new RenderFontDefaults();
FontInfoBase::s_SetFontDefaultList(Globals.pFontDefaultList);
// Check if this conhost is allowed to delegate its activities to another.
// If so, look up the registered default console handler.
bool isEnabled = false;
if (SUCCEEDED(Microsoft::Console::Internal::DefaultApp::CheckDefaultAppPolicy(isEnabled) && isEnabled))
{
Globals.pDeviceComm = new ConDrvDeviceComm(Server);
Globals.launchArgs = *args;
Globals.uiOEMCP = GetOEMCP();
Globals.uiWindowsCP = GetACP();
Globals.pFontDefaultList = new RenderFontDefaults();
FontInfoBase::s_SetFontDefaultList(Globals.pFontDefaultList);
IID delegationClsid;
if (SUCCEEDED(DelegationConfig::s_GetConsole(delegationClsid)))
{
Globals.handoffConsoleClsid = delegationClsid;
}
}
CATCH_RETURN();
// Removed allocation of scroll buffer here.
return S_OK;
}
CATCH_RETURN()
static bool s_IsOnDesktop()
{

View File

@ -26,4 +26,6 @@ PWSTR TranslateConsoleTitle(_In_ PCWSTR pwszConsoleTitle, const BOOL fUnexpand,
[[nodiscard]] NTSTATUS ConsoleAllocateConsole(PCONSOLE_API_CONNECTINFO p);
[[nodiscard]] NTSTATUS RemoveConsole(_In_ ConsoleProcessHandle* ProcessData);
[[nodiscard]] bool ConsoleConnectionDeservesVisibleWindow(PCONSOLE_API_CONNECTINFO p);
void ConsoleCheckDebug();

View File

@ -44,4 +44,9 @@ namespace Microsoft::Console::Internal
{
[[nodiscard]] HRESULT TrySetDarkMode(HWND hwnd) noexcept;
}
namespace DefaultApp
{
[[nodiscard]] HRESULT CheckDefaultAppPolicy(bool& isEnabled) noexcept;
}
}

View File

@ -29,3 +29,10 @@ void EdpPolicy::AuditClipboard(const std::wstring_view /*destinationName*/) noex
{
return S_FALSE;
}
[[nodiscard]]
HRESULT DefaultApp::CheckDefaultAppPolicy(bool& isEnabled) noexcept
{
isEnabled = false;
return S_OK;
}

View File

@ -0,0 +1,230 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "DelegationConfig.hpp"
#include "RegistrySerialization.hpp"
#include <wil/resource.h>
#include <wil/winrt.h>
#include <windows.foundation.collections.h>
#include <Windows.ApplicationModel.h>
#include <Windows.ApplicationModel.AppExtensions.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::ApplicationModel;
using namespace ABI::Windows::ApplicationModel::AppExtensions;
#pragma hdrstop
#define DELEGATION_CONSOLE_KEY_NAME L"DelegationConsole"
#define DELEGATION_TERMINAL_KEY_NAME L"DelegationTerminal"
#define DELEGATION_CONSOLE_EXTENSION_NAME L"com.microsoft.windows.console.host"
#define DELEGATION_TERMINAL_EXTENSION_NAME L"com.microsoft.windows.terminal.host"
template<typename T, typename std::enable_if<std::is_base_of<DelegationConfig::DelegationBase, T>::value>::type* = nullptr>
HRESULT _lookupCatalog(PCWSTR extensionName, std::vector<T>& vec) noexcept
{
vec.clear();
auto coinit = wil::CoInitializeEx(COINIT_MULTITHREADED);
ComPtr<IAppExtensionCatalogStatics> catalogStatics;
RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_AppExtensions_AppExtensionCatalog).Get(), &catalogStatics));
ComPtr<IAppExtensionCatalog> catalog;
RETURN_IF_FAILED(catalogStatics->Open(HStringReference(extensionName).Get(), &catalog));
ComPtr<IAsyncOperation<IVectorView<AppExtension*>*>> findOperation;
RETURN_IF_FAILED(catalog->FindAllAsync(&findOperation));
ComPtr<IVectorView<AppExtension*>> extensionList;
RETURN_IF_FAILED(wil::wait_for_completion_nothrow(findOperation.Get(), &extensionList));
UINT extensionCount;
RETURN_IF_FAILED(extensionList->get_Size(&extensionCount));
for (UINT index = 0; index < extensionCount; index++)
{
T extensionMetadata;
ComPtr<IAppExtension> extension;
RETURN_IF_FAILED(extensionList->GetAt(index, &extension));
ComPtr<IPackage> extensionPackage;
RETURN_IF_FAILED(extension->get_Package(&extensionPackage));
ComPtr<IPackageId> extensionPackageId;
RETURN_IF_FAILED(extensionPackage->get_Id(&extensionPackageId));
HString publisherId;
RETURN_IF_FAILED(extensionPackageId->get_PublisherId(publisherId.GetAddressOf()));
// PackageId.Name
HString name;
RETURN_IF_FAILED(extensionPackageId->get_Name(name.GetAddressOf()));
extensionMetadata.name = std::wstring{ name.GetRawBuffer(nullptr) };
// PackageId.Version
HString publisher;
RETURN_IF_FAILED(extensionPackageId->get_Publisher(publisher.GetAddressOf()));
extensionMetadata.author = std::wstring{ publisher.GetRawBuffer(nullptr) };
// Fetch the custom properties XML out of the extension information
ComPtr<IAsyncOperation<IPropertySet*>> propertiesOperation;
RETURN_IF_FAILED(extension->GetExtensionPropertiesAsync(&propertiesOperation));
// Wait for async to complete and return the property set.
ComPtr<IPropertySet> properties;
RETURN_IF_FAILED(wil::wait_for_completion_nothrow(propertiesOperation.Get(), &properties));
// We can't do anything on a set, but it must also be convertible to this type of map per the Windows.Foundation specs for this
ComPtr<IMap<HSTRING, IInspectable*>> map;
RETURN_IF_FAILED(properties.As(&map));
// Looking it up is going to get us an inspectable
ComPtr<IInspectable> inspectable;
RETURN_IF_FAILED(map->Lookup(HStringReference(L"Clsid").Get(), &inspectable));
// Unfortunately that inspectable is another set because we're dealing with XML data payload that we put in the manifest.
ComPtr<IPropertySet> anotherSet;
RETURN_IF_FAILED(inspectable.As(&anotherSet));
// And we can't look at sets directly, so move it to map.
ComPtr<IMap<HSTRING, IInspectable*>> anotherMap;
RETURN_IF_FAILED(anotherSet.As(&anotherMap));
// Use the magic value of #text to get the body between the XML tags. And of course it's an obtuse Inspectable again.
ComPtr<IInspectable> anotherInspectable;
RETURN_IF_FAILED(anotherMap->Lookup(HStringReference(L"#text").Get(), &anotherInspectable));
// But this time that Inspectable is an IPropertyValue, which is a PROPVARIANT in a trenchcoat.
ComPtr<IPropertyValue> propValue;
RETURN_IF_FAILED(anotherInspectable.As(&propValue));
// Check the type of the variant
PropertyType propType;
RETURN_IF_FAILED(propValue->get_Type(&propType));
// If we're not a string, bail because I don't know what's going on.
if (propType != PropertyType::PropertyType_String)
{
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
// Get that string out.
HString value;
RETURN_IF_FAILED(propValue->GetString(value.GetAddressOf()));
// Holy cow. It should be a GUID. Try to parse it.
IID iid;
RETURN_IF_FAILED(IIDFromString(value.GetRawBuffer(nullptr), &iid));
extensionMetadata.clsid = iid;
vec.emplace_back(std::move(extensionMetadata));
}
return S_OK;
}
[[nodiscard]] HRESULT DelegationConfig::s_GetAvailableConsoles(std::vector<DelegationConsole>& consoles) noexcept
try
{
return _lookupCatalog(DELEGATION_CONSOLE_EXTENSION_NAME, consoles);
}
CATCH_RETURN()
[[nodiscard]] HRESULT DelegationConfig::s_GetAvailableTerminals(std::vector<DelegationTerminal>& terminals) noexcept
try
{
return _lookupCatalog(DELEGATION_TERMINAL_EXTENSION_NAME, terminals);
}
CATCH_RETURN()
[[nodiscard]] HRESULT DelegationConfig::s_SetConsole(const DelegationConsole& console) noexcept
{
return s_Set(DELEGATION_CONSOLE_KEY_NAME, console.clsid);
}
[[nodiscard]] HRESULT DelegationConfig::s_SetTerminal(const DelegationTerminal& terminal) noexcept
{
return s_Set(DELEGATION_TERMINAL_KEY_NAME, terminal.clsid);
}
[[nodiscard]] HRESULT DelegationConfig::s_GetConsole(IID& iid) noexcept
{
return s_Get(DELEGATION_CONSOLE_KEY_NAME, iid);
}
[[nodiscard]] HRESULT DelegationConfig::s_GetTerminal(IID& iid) noexcept
{
return s_Get(DELEGATION_TERMINAL_KEY_NAME, iid);
}
[[nodiscard]] HRESULT DelegationConfig::s_Get(PCWSTR value, IID& iid) noexcept
{
wil::unique_hkey currentUserKey;
wil::unique_hkey consoleKey;
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_OpenConsoleKey(&currentUserKey, &consoleKey));
wil::unique_hkey startupKey;
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_OpenKey(consoleKey.get(), L"%%Startup", &startupKey));
DWORD bytesNeeded = 0;
NTSTATUS result = RegistrySerialization::s_QueryValue(startupKey.get(),
value,
0,
REG_SZ,
nullptr,
&bytesNeeded);
if (NTSTATUS_FROM_WIN32(ERROR_SUCCESS) != result)
{
RETURN_NTSTATUS(result);
}
auto buffer = std::make_unique<wchar_t[]>(bytesNeeded / sizeof(wchar_t));
DWORD bytesUsed = 0;
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_QueryValue(startupKey.get(),
value,
bytesNeeded,
REG_SZ,
reinterpret_cast<BYTE*>(buffer.get()),
&bytesUsed));
RETURN_IF_FAILED(IIDFromString(buffer.get(), &iid));
return S_OK;
}
[[nodiscard]] HRESULT DelegationConfig::s_Set(PCWSTR value, const CLSID clsid) noexcept
try
{
wil::unique_hkey currentUserKey;
wil::unique_hkey consoleKey;
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_OpenConsoleKey(&currentUserKey, &consoleKey));
wil::unique_hkey startupKey;
RETURN_IF_NTSTATUS_FAILED(RegistrySerialization::s_OpenKey(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() + 1) * sizeof(wchar_t))));
return S_OK;
}
CATCH_RETURN()

View File

@ -0,0 +1,48 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- DelegationConfig.hpp
Abstract:
- This module is used for looking up delegation handlers for the launch of the default console hosting environment
Author(s):
- Michael Niksa (MiNiksa) 31-Aug-2020
--*/
#pragma once
class DelegationConfig
{
public:
struct DelegationBase
{
CLSID clsid;
std::wstring name;
std::wstring author;
};
struct DelegationConsole : public DelegationBase
{
};
struct DelegationTerminal : public DelegationBase
{
};
[[nodiscard]] static HRESULT s_GetAvailableConsoles(std::vector<DelegationConsole>& consoles) noexcept;
[[nodiscard]] static HRESULT s_GetAvailableTerminals(std::vector<DelegationTerminal>& terminals) noexcept;
[[nodiscard]] static HRESULT s_SetConsole(const DelegationConsole& console) noexcept;
[[nodiscard]] static HRESULT s_SetTerminal(const DelegationTerminal& terminal) noexcept;
[[nodiscard]] static HRESULT s_GetConsole(IID& iid) noexcept;
[[nodiscard]] static HRESULT s_GetTerminal(IID& iid) noexcept;
private:
[[nodiscard]] static HRESULT s_Get(PCWSTR value, IID& iid) noexcept;
[[nodiscard]] static HRESULT s_Set(PCWSTR value, const CLSID clsid) noexcept;
};

View File

@ -6,10 +6,11 @@
<RootNamespace>propslib</RootNamespace>
<ProjectName>PropertiesLibrary</ProjectName>
<TargetName>ConProps</TargetName>
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<Import Project="$(SolutionDir)src\common.build.pre.props" />
<ItemGroup>
<ClCompile Include="DelegationConfig.cpp" />
<ClCompile Include="RegistrySerialization.cpp" />
<ClCompile Include="ShortcutSerialization.cpp" />
<ClCompile Include="TrueTypeFontList.cpp" />
@ -19,6 +20,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="conpropsp.hpp" />
<ClInclude Include="DelegationConfig.hpp" />
<ClInclude Include="RegistrySerialization.hpp" />
<ClInclude Include="ShortcutSerialization.hpp" />
<ClInclude Include="TrueTypeFontList.hpp" />

View File

@ -27,6 +27,9 @@
<ClCompile Include="precomp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DelegationConfig.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="conpropsp.hpp">
@ -44,5 +47,8 @@
<ClInclude Include="TrueTypeFontList.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DelegationConfig.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -42,10 +42,12 @@ PRECOMPILED_CXX = 1
PRECOMPILED_INCLUDE = precomp.h
SOURCES = \
DelegationConfig.cpp \
ShortcutSerialization.cpp \
RegistrySerialization.cpp \
TrueTypeFontList.cpp \
INCLUDES = \
$(ABI_INC_PATH)\; \
$(INCLUDES); \
..\inc; \

View File

@ -173,3 +173,12 @@ ConDrvDeviceComm::~ConDrvDeviceComm()
{
return reinterpret_cast<void*>(handleId);
}
// Routine Description:
// - Provides acccess to the raw server handle so it can be used to hand off
// the session to another console host server.
[[nodiscard]] HRESULT ConDrvDeviceComm::GetServerHandle(_Out_ HANDLE* pHandle) const
{
*pHandle = _Server.get();
return S_OK;
}

View File

@ -40,6 +40,8 @@ public:
[[nodiscard]] ULONG_PTR PutHandle(const void*) override;
[[nodiscard]] void* GetHandle(ULONG_PTR) const override;
[[nodiscard]] HRESULT GetServerHandle(_Out_ HANDLE* pHandle) const override;
private:
[[nodiscard]] HRESULT _CallIoctl(_In_ DWORD dwIoControlCode,
_In_reads_bytes_opt_(cbInBufferSize) PVOID pInBuffer,

View File

@ -35,4 +35,6 @@ public:
[[nodiscard]] virtual ULONG_PTR PutHandle(const void*) = 0;
[[nodiscard]] virtual void* GetHandle(ULONG_PTR) const = 0;
[[nodiscard]] virtual HRESULT GetServerHandle(_Out_ HANDLE* pHandle) const = 0;
};

View File

@ -16,7 +16,12 @@
#include "../interactivity/inc/ServiceLocator.hpp"
#include "../types/inc/utils.hpp"
#include "IConsoleHandoff.h"
using namespace Microsoft::Console::Interactivity;
using namespace Microsoft::Console::Utils;
// From ntstatus.h, which we cannot include without causing a bunch of other conflicts. So we just include the one code we need.
//
@ -142,7 +147,8 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleCloseObject(_In_ PCONSOLE_API_MSG pMessag
// - The response data to this request message.
PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API_MSG pReceiveMsg)
{
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
Globals& Globals = ServiceLocator::LocateGlobals();
CONSOLE_INFORMATION& gci = Globals.getConsoleInformation();
Telemetry::Instance().LogApiCall(Telemetry::ApiCall::AttachConsole);
ConsoleProcessHandle* ProcessData = nullptr;
@ -159,6 +165,54 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
goto Error;
}
// If we are NOT a PTY session (headless)...
// we have FOUND a CLSID for a different console to be the default startup handler...
// we are NOT already receiving an inbound console connection handoff...
// and the client app is going to end up showing a window...
// then attempt to delegate the startup to the registered replacement.
if (!Globals.launchArgs.IsHeadless() && Globals.handoffConsoleClsid && !Globals.handoffTarget && ConsoleConnectionDeservesVisibleWindow(&Cac))
{
try
{
// Go get ourselves some COM.
auto coinit = wil::CoInitializeEx(COINIT_MULTITHREADED);
// Get the class/interface to the handoff handler. Local machine only.
::Microsoft::WRL::ComPtr<IConsoleHandoff> handoff;
THROW_IF_FAILED(CoCreateInstance(Globals.handoffConsoleClsid.value(), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&handoff)));
// Pack up just enough of the attach message for the other console to process it.
// NOTE: It can and will pick up the size/title/etc parameters from the driver again.
CONSOLE_PORTABLE_ATTACH_MSG msg{};
msg.IdHighPart = pReceiveMsg->Descriptor.Identifier.HighPart;
msg.IdLowPart = pReceiveMsg->Descriptor.Identifier.LowPart;
msg.Process = pReceiveMsg->Descriptor.Process;
msg.Object = pReceiveMsg->Descriptor.Object;
msg.Function = pReceiveMsg->Descriptor.Function;
msg.InputSize = pReceiveMsg->Descriptor.InputSize;
msg.OutputSize = pReceiveMsg->Descriptor.OutputSize;
// Attempt to get server handle out of our own communication stack to pass it on.
HANDLE serverHandle;
THROW_IF_FAILED(Globals.pDeviceComm->GetServerHandle(&serverHandle));
// Okay, moment of truth! If they say they successfully took it over, we're going to clean up.
// If they fail, we'll throw here and it'll log and we'll just start normally.
THROW_IF_FAILED(handoff->EstablishHandoff(serverHandle,
Globals.hInputEvent.get(),
&msg));
// Unlock in case anything tries to spool down as we exit.
UnlockConsole();
// We've handed off responsibility. Exit process to clean up any outstanding things we have open.
ExitProcess(S_OK);
}
CATCH_LOG(); // Just log, don't do anything more. We'll move on to launching normally on failure.
}
Status = NTSTATUS_FROM_HRESULT(gci.ProcessHandleList.AllocProcessData(dwProcessId,
dwThreadId,
Cac.ProcessGroupId,

View File

@ -57,6 +57,16 @@
<ClInclude Include="..\WaitTerminationReason.h" />
<ClInclude Include="..\WinNTControl.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\host\dll\Host.DLL.vcxproj">
<Project>{e437b604-3e98-4f40-a927-e173e818ea4b}</Project>
</ProjectReference>
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(IntDir)..\Host.ProxyDll;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
<Import Project="$(SolutionDir)src\common.build.post.props" />
</Project>

View File

@ -72,6 +72,9 @@
<ClCompile Include="..\ProcessPolicy.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\ConsoleShimPolicy.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\precomp.h">
@ -137,5 +140,11 @@
<ClInclude Include="..\ProcessPolicy.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\ConsoleShimPolicy.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
</ItemGroup>
</Project>

View File

@ -54,4 +54,5 @@ SOURCES= \
INCLUDES= \
$(INCLUDES); \
$(WINCORE_OBJ_PATH)\console\open\src\host\proxy\$(O); \
..; \