Merged PR 5770253: [Git2Git] Merged PR 5760120: Add propsheet chooser to Windows

[Git2Git] Merged PR 5760120: Add propsheet chooser to Windows

Now the inbox console propsheet can choose which terminal is default

Related work items: MSFT-32007202 #492

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev d80f506858bd990c267de6cefae7ff55707b3a57
This commit is contained in:
Dustin Howett 2021-03-10 01:19:04 +00:00
parent ce99c2a349
commit 3909cc103a
15 changed files with 470 additions and 29 deletions

View file

@ -56,7 +56,7 @@ try
if (SUCCEEDED(Microsoft::Console::Internal::DefaultApp::CheckDefaultAppPolicy(isEnabled) && isEnabled))
{
IID delegationClsid;
if (SUCCEEDED(DelegationConfig::s_GetConsole(delegationClsid)))
if (SUCCEEDED(DelegationConfig::s_GetDefaultConsoleId(delegationClsid)))
{
Globals.handoffConsoleClsid = delegationClsid;
}

View file

@ -21,7 +21,7 @@ namespace til::pmr
// get_default_resource below forces it to be included by the compiler.
// I *believe* that if the VC++ Runtime is updated to include the PMR source,
// this will safely no-op (since it's an ALTERNATENAME).
#if defined(_M_AMD64) || defined(_M_ARM64)
#if defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_ARM)
#pragma comment(linker, "/ALTERNATENAME:_Aligned_get_default_resource=TIL_PMR_Aligned_get_default_resource")
#else
#pragma comment(linker, "/ALTERNATENAME:__Aligned_get_default_resource=_TIL_PMR_Aligned_get_default_resource")

View file

@ -6,6 +6,8 @@
#include "OptionsPage.h" // For InitializeCursorSize
#include "ColorControl.h"
#include <functional>
#include "../propslib/DelegationConfig.hpp"
#include "../types/inc/User32Utils.hpp"
// From conattrs.h
const COLORREF INVALID_COLOR = 0xffffffff;
@ -87,6 +89,41 @@ void _UpdateTextAndScroll(const HWND hDlg,
SendDlgItemMessage(hDlg, scrollItem, UDM_SETPOS, 0, MAKELONG(value, 0));
}
void _PrepDefAppCombo(const HWND hDlg,
const int dlgItem,
const std::vector<DelegationConfig::DelegationPackage>& list,
const DelegationConfig::DelegationPackage& selected)
{
const HWND hCombo = GetDlgItem(hDlg, dlgItem);
ComboBox_ResetContent(hCombo);
DWORD selectedIndex = 0;
for (DWORD i = 0; i < gsl::narrow<DWORD>(list.size()); ++i)
{
auto& item = list[i];
// An empty CLSID is a sentinel for the inbox console.
if (item.terminal.clsid == CLSID{ 0 })
{
const auto name = GetStringResource(IDS_TERMINAL_DEF_INBOX);
ComboBox_AddString(hCombo, name.c_str());
}
else
{
ComboBox_AddString(hCombo, item.terminal.name.c_str());
}
ComboBox_SetItemData(hCombo, i, &item);
if (selected == item)
{
selectedIndex = i;
}
}
ComboBox_SetCurSel(hCombo, selectedIndex);
ComboBox_Enable(hCombo, TRUE);
}
bool InitTerminalDialog(const HWND hDlg) noexcept
{
// Initialize the global handle to this dialog
@ -181,6 +218,11 @@ bool InitTerminalDialog(const HWND hDlg) noexcept
CheckDlgButton(hDlg, IDD_DISABLE_SCROLLFORWARD, gpStateInfo->TerminalScrolling);
_PrepDefAppCombo(hDlg,
IDD_TERMINAL_COMBO_DEFTERM,
g_availablePackages,
g_selectedPackage);
return true;
}
@ -341,11 +383,27 @@ bool TerminalDlgCommand(const HWND hDlg, const WORD item, const WORD command) no
break;
}
case IDD_DISABLE_SCROLLFORWARD:
{
gpStateInfo->TerminalScrolling = IsDlgButtonChecked(hDlg, IDD_DISABLE_SCROLLFORWARD);
UpdateApplyButton(hDlg);
handled = true;
break;
}
case IDD_TERMINAL_COMBO_DEFTERM:
{
if (CBN_SELCHANGE == command)
{
const HWND hCombo = GetDlgItem(hDlg, IDD_TERMINAL_COMBO_DEFTERM);
const DWORD comboItem = ComboBox_GetCurSel(hCombo);
if (CB_ERR != comboItem)
{
const auto pPackage = reinterpret_cast<const DelegationConfig::DelegationPackage* const>(ComboBox_GetItemData(hCombo, comboItem));
g_selectedPackage = *pPackage;
}
}
break;
}
}
return handled;
}

View file

@ -19,6 +19,8 @@ Revision History:
#include "precomp.h"
#include "conint.h"
#pragma hdrstop
UINT gnCurrentPage;
@ -94,6 +96,11 @@ void SaveConsoleSettingsIfNeeded(const HWND hwnd)
gpStateInfo->FaceName[0] = TEXT('\0');
}
if (g_defAppEnabled)
{
LOG_IF_FAILED(DelegationConfig::s_SetDefaultByPackage(g_selectedPackage));
}
if (gpStateInfo->LinkTitle != nullptr)
{
SetGlobalRegistryValues();
@ -545,7 +552,14 @@ BOOL PopulatePropSheetPageArray(_Out_writes_(cPsps) PROPSHEETPAGE* pPsp, const s
{
pTerminalPage->dwSize = sizeof(PROPSHEETPAGE);
pTerminalPage->hInstance = ghInstance;
pTerminalPage->pszTemplate = MAKEINTRESOURCE(DID_TERMINAL);
if (g_defAppEnabled)
{
pTerminalPage->pszTemplate = MAKEINTRESOURCE(DID_TERMINAL_WITH_DEFTERM);
}
else
{
pTerminalPage->pszTemplate = MAKEINTRESOURCE(DID_TERMINAL);
}
pTerminalPage->pfnDlgProc = TerminalDlgProc;
pTerminalPage->lParam = TERMINAL_PAGE_INDEX;
pTerminalPage->dwFlags = PSP_DEFAULT;
@ -611,6 +625,15 @@ INT_PTR ConsolePropertySheet(__in HWND hWnd, __in PCONSOLE_STATE_INFO pStateInfo
// since we just triggered font enumeration, recreate our font handles to adapt for DPI
RecreateFontHandles(hWnd);
//
// Find the available default console/terminal packages
//
if (SUCCEEDED(Microsoft::Console::Internal::DefaultApp::CheckDefaultAppPolicy(g_defAppEnabled)) && g_defAppEnabled)
{
LOG_IF_FAILED(DelegationConfig::s_GetAvailablePackages(g_availablePackages, g_selectedPackage));
}
//
// Get the current page number
//

View file

@ -58,6 +58,7 @@ Revision History:
// unused 16
#define IDS_TOOLTIP_OPACITY 17
#define IDS_TOOLTIP_INTERCEPT_COPY_PASTE 18
#define IDS_TERMINAL_DEF_INBOX 19
// clang-format on
void MakeAltRasterFont(

View file

@ -534,6 +534,17 @@ END
#define T_SCROLL_W 100
#define T_SCROLL_H 40
// default application group box
#define T_DEFAPP_X T_CCOLOR_X
#define T_DEFAPP_Y T_SCROLL_Y
#define T_DEFAPP_W T_CCOLOR_W
#define T_DEFAPP_H T_SCROLL_H
#define T_DEFTERM_X (T_DEFAPP_X+P_1)
#define T_DEFTERM_Y (T_DEFAPP_Y+P_2)
#define T_DEFTERM_W (T_DEFAPP_W-P_4-P_4)
#define T_DEFTERM_H 25
#define UPDOWN_STYLES (UDS_AUTOBUDDY | UDS_SETBUDDYINT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_ALIGNRIGHT)
DID_TERMINAL DIALOG 0, 0, 245, 226
CAPTION " Terminal "
@ -624,6 +635,98 @@ BEGIN
IDD_HELP_TERMINAL, "SysLink", WS_TABSTOP, 10, 225, 200, 10
END
DID_TERMINAL_WITH_DEFTERM DIALOG 0, 0, 245, 226
CAPTION " Terminal "
STYLE WS_VISIBLE | WS_CAPTION | WS_CHILD | DS_MODALFRAME
FONT 8,"MS Shell Dlg"
BEGIN
// GROUPBOX text, id, x, y, width, height [, style [, extended-style]]
// CONTROL text, id, class, style, x, y, width, height [, extended-style]
GROUPBOX "Terminal Colors", -1, T_COLORS_X, T_COLORS_Y, T_COLORS_W, T_COLORS_H, WS_GROUP
AUTOCHECKBOX "Use Separate Foreground", IDD_USE_TERMINAL_FG, T_COLORS_X+P_1, T_COLORS_CHECK_Y, T_COLORS_FG_W, 10
CONTROL "", IDD_TERMINAL_FGCOLOR, "SimpleColor", WS_BORDER | WS_CHILD | WS_GROUP ,
T_COLORS_X+P_2, T_COLORS_RED_Y, COLOR_SIZE, COLOR_SIZE
LTEXT "Red:", -1, T_COLORS_FG_TEXT_X, T_COLORS_RED_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_FG_RED, T_COLORS_FG_INPUT_X, T_COLORS_RED_Y, T_COLORS_EDIT_W, T_COLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_FG_REDSCROLL, UPDOWN_CLASS,
UPDOWN_STYLES, 0, 0, 0, 0
LTEXT "Green:", -1, T_COLORS_FG_TEXT_X, T_COLORS_GREEN_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_FG_GREEN, T_COLORS_FG_INPUT_X, T_COLORS_GREEN_Y, T_COLORS_EDIT_W, T_COLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_FG_GREENSCROLL, UPDOWN_CLASS,
UPDOWN_STYLES, 0, 0, 0, 0
LTEXT "Blue:", -1, T_COLORS_FG_TEXT_X, T_COLORS_BLUE_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_FG_BLUE, T_COLORS_FG_INPUT_X, T_COLORS_BLUE_Y, T_COLORS_EDIT_W, T_COLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_FG_BLUESCROLL, UPDOWN_CLASS,
UPDOWN_STYLES, 0, 0, 0, 0
AUTOCHECKBOX "Use Separate Background", IDD_USE_TERMINAL_BG, T_COLORS_BG_X, T_COLORS_CHECK_Y, T_COLORS_FG_W, 10
CONTROL "", IDD_TERMINAL_BGCOLOR, "SimpleColor", WS_BORDER | WS_CHILD | WS_GROUP ,
T_COLORS_BG_X, T_COLORS_RED_Y, COLOR_SIZE, COLOR_SIZE
LTEXT "Red:", -1, T_COLORS_BG_TEXT_X, T_COLORS_RED_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_BG_RED, T_COLORS_BG_INPUT_X, T_COLORS_RED_Y, T_COLORS_EDIT_W, T_COLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_BG_REDSCROLL, UPDOWN_CLASS,
UPDOWN_STYLES, 0, 0, 0, 0
LTEXT "Green:", -1, T_COLORS_BG_TEXT_X, T_COLORS_GREEN_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_BG_GREEN, T_COLORS_BG_INPUT_X, T_COLORS_GREEN_Y, T_COLORS_EDIT_W, T_COLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_BG_GREENSCROLL, UPDOWN_CLASS,
UPDOWN_STYLES, 0, 0, 0, 0
LTEXT "Blue:", -1, T_COLORS_BG_TEXT_X, T_COLORS_BLUE_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_BG_BLUE, T_COLORS_BG_INPUT_X, T_COLORS_BLUE_Y, T_COLORS_EDIT_W, T_COLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_BG_BLUESCROLL, UPDOWN_CLASS,
UPDOWN_STYLES, 0, 0, 0, 0
GROUPBOX "Cursor Shape", -1, T_CSTYLE_X, T_CSTYLE_Y, T_CSTYLE_W, T_CSTYLE_H
AUTORADIOBUTTON "Use Legacy Style", IDD_TERMINAL_LEGACY_CURSOR, T_CSTYLE_X+P_1, T_CSTYLE_R_1_Y, T_CSTYLE_R_W, T_CSTYLE_R_H, WS_TABSTOP|WS_GROUP
AUTORADIOBUTTON "Underscore", IDD_TERMINAL_UNDERSCORE, T_CSTYLE_X+P_1, T_CSTYLE_R_2_Y, T_CSTYLE_R_W, T_CSTYLE_R_H,
AUTORADIOBUTTON "Vertical Bar", IDD_TERMINAL_VERTBAR, T_CSTYLE_X+P_1, T_CSTYLE_R_3_Y, T_CSTYLE_R_W, T_CSTYLE_R_H,
AUTORADIOBUTTON "Empty Box", IDD_TERMINAL_EMPTYBOX, T_CSTYLE_X+P_1, T_CSTYLE_R_4_Y, T_CSTYLE_R_W, T_CSTYLE_R_H,
AUTORADIOBUTTON "Solid Box", IDD_TERMINAL_SOLIDBOX, T_CSTYLE_X+P_1, T_CSTYLE_R_5_Y, T_CSTYLE_R_W, T_CSTYLE_R_H,
GROUPBOX "Cursor Colors", -1, T_CCOLOR_X, T_CCOLOR_Y, T_CCOLOR_W, T_CCOLOR_H, WS_GROUP
AUTORADIOBUTTON "Inverse Color", IDD_TERMINAL_INVERSE_CURSOR, T_CCOLOR_X+P_1, T_CSTYLE_R_1_Y, T_CCOLOR_R_W, T_CSTYLE_R_H, WS_TABSTOP|WS_GROUP
AUTORADIOBUTTON "Use Color", IDD_TERMINAL_CURSOR_USECOLOR, T_CCOLOR_X+P_1, T_CSTYLE_R_2_Y, T_CCOLOR_R_W, T_CSTYLE_R_H,
CONTROL "", IDD_TERMINAL_CURSOR_COLOR, "SimpleColor", WS_BORDER | WS_CHILD | WS_GROUP,
T_CCOLOR_X+P_2, T_CSTYLE_R_3_Y, COLOR_SIZE, COLOR_SIZE
LTEXT "Red:", -1, T_CCOLOR_TEXT_X, T_CCOLOR_R_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_CURSOR_RED, T_CCOLOR_EDIT_X, T_CCOLOR_R_Y, T_CCOLORS_EDIT_W, T_CCOLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_CURSOR_REDSCROLL, UPDOWN_CLASS, UPDOWN_STYLES, 0, 0, 0, 0
LTEXT "Green:", -1, T_CCOLOR_TEXT_X, T_CCOLOR_G_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_CURSOR_GREEN, T_CCOLOR_EDIT_X, T_CCOLOR_G_Y, T_CCOLORS_EDIT_W, T_CCOLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_CURSOR_GREENSCROLL, UPDOWN_CLASS, UPDOWN_STYLES, 0, 0, 0, 0
LTEXT "Blue:", -1, T_CCOLOR_TEXT_X, T_CCOLOR_B_Y, T_COLORS_TEXT_W, 9
EDITTEXT IDD_TERMINAL_CURSOR_BLUE, T_CCOLOR_EDIT_X, T_CCOLOR_B_Y, T_CCOLORS_EDIT_W, T_CCOLORS_EDIT_H, WS_TABSTOP | WS_GROUP | ES_AUTOHSCROLL
CONTROL "", IDD_TERMINAL_CURSOR_BLUESCROLL, UPDOWN_CLASS, UPDOWN_STYLES, 0, 0, 0, 0
GROUPBOX "Terminal Scrolling", -1, T_SCROLL_X, T_SCROLL_Y, T_SCROLL_W, T_SCROLL_H
AUTOCHECKBOX "Disable Scroll-Forward", IDD_DISABLE_SCROLLFORWARD, T_SCROLL_X+P_1, T_SCROLL_Y+P_2, T_SCROLL_W-P_4-P_4, 10
GROUPBOX "Default Terminal Application", -1, T_DEFAPP_X, T_DEFAPP_Y, T_DEFAPP_W, T_DEFAPP_H
COMBOBOX IDD_TERMINAL_COMBO_DEFTERM, T_DEFTERM_X+P_0, T_DEFTERM_Y, T_DEFTERM_W, 10, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Find out more about <A HREF=""https://go.microsoft.com/fwlink/?linkid=2028595"">experimental terminal settings</A>",
IDD_HELP_TERMINAL, "SysLink", WS_TABSTOP, 10, 225, 200, 10
END
//
// Strings
@ -646,6 +749,7 @@ BEGIN
IDS_TOOLTIP_EDIT_KEYS, "Enable enhanced keyboard editing on command line."
IDS_TOOLTIP_OPACITY, "Adjust the transparency of the console window."
IDS_TOOLTIP_INTERCEPT_COPY_PASTE, "Use Ctrl+Shift+C/V as copy/paste shortcuts, regardless of input mode"
IDS_TERMINAL_DEF_INBOX, "Windows Console Host"
END

View file

@ -164,6 +164,8 @@ Revision History:
#define IDD_TERMINAL_CURSOR_GREEN 630
#define IDD_TERMINAL_CURSOR_BLUE 631
#define IDD_HELP_TERMINAL 632
#define DID_TERMINAL_WITH_DEFTERM 640
#define IDD_TERMINAL_COMBO_DEFTERM 641
#define BM_TRUETYPE_ICON 1000

View file

@ -59,3 +59,7 @@ COLORREF g_fakeCursorColor = RGB(242, 242, 242); // Default bright white
HWND g_hTerminalDlg = static_cast<HWND>(INVALID_HANDLE_VALUE);
HWND g_hOptionsDlg = static_cast<HWND>(INVALID_HANDLE_VALUE);
bool g_defAppEnabled = false;
std::vector<DelegationConfig::DelegationPackage> g_availablePackages;
DelegationConfig::DelegationPackage g_selectedPackage;

View file

@ -14,6 +14,7 @@
#pragma once
#include "font.h"
#include "../propslib/DelegationConfig.hpp"
extern HINSTANCE ghInstance;
extern PCONSOLE_STATE_INFO gpStateInfo;
@ -54,3 +55,7 @@ extern COLORREF g_fakeCursorColor;
extern HWND g_hTerminalDlg;
extern HWND g_hOptionsDlg;
extern bool g_defAppEnabled;
extern std::vector<DelegationConfig::DelegationPackage> g_availablePackages;
extern DelegationConfig::DelegationPackage g_selectedPackage;

View file

@ -53,6 +53,9 @@
<ProjectReference Include="..\propslib\propslib.vcxproj">
<Project>{345fd5a4-b32b-4f29-bd1c-b033bd2c35cc}</Project>
</ProjectReference>
<ProjectReference Include="..\internal\internal.vcxproj">
<Project>{EF3E32A7-5FF6-42B4-B6E2-96CD7D033F00}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="console.def" />

View file

@ -84,6 +84,8 @@ TARGETLIBS = \
$(ONECORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\onecore_internal.lib \
$(ONECORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\onecoreuap_internal.lib \
$(ONECOREUAP_INTERNAL_SDK_LIB_PATH)\onecoreuapuuid.lib \
$(ONECORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-dwmapi-ext-l1.lib \
$(MINCORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-edputil-policy-l1.lib \
$(MINCORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-gdi-dc-l1.lib \
$(MINCORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-gdi-dc-create-l1.lib \
$(MINCORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-gdi-draw-l1.lib \
@ -100,10 +102,39 @@ TARGETLIBS = \
$(MINCORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-rtcore-ntuser-syscolors-l1.lib \
$(MINCORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-rtcore-ntuser-sysparams-l1.lib\
$(MINCORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-shell-shell32-l1.lib \
$(MINCORE_INTERNAL_PRIV_SDK_LIB_VPATH_L)\ext-ms-win-uxtheme-themes-l1.lib \
$(ONECOREBASE_INTERNAL_LIB_VPATH_L)\ext-ms-win-appmodel-shellexecute-l1.lib \
$(ONECOREWINDOWS_INTERNAL_LIB_PATH_L)\ext-ms-win-gdi-internal-desktop-l1-1-1.lib \
$(WINCORE_OBJ_PATH)\console\conint\$(O)\conint.lib \
$(WINCORE_OBJ_PATH)\console\open\src\propslib\$(O)\conprops.lib \
DELAYLOAD = \
ext-ms-win-dwmapi-ext-l1.dll; \
ext-ms-win-edputil-policy-l1.dll; \
ext-ms-win-uxtheme-themes-l1.dll; \
ext-ms-win-shell32-shellfolders-l1.dll; \
ext-ms-win-gdi-dc-l1.dll; \
ext-ms-win-gdi-dc-create-l1.dll; \
ext-ms-win-gdi-draw-l1.dll; \
ext-ms-win-gdi-font-l1.dll; \
ext-ms-win-ntuser-dialogbox-l1.dll; \
ext-ms-win-ntuser-draw-l1.dll; \
ext-ms-win-ntuser-keyboard-l1.dll; \
ext-ms-win-ntuser-gui-l1.dll; \
ext-ms-win-ntuser-misc-l1.dll; \
ext-ms-win-ntuser-window-l1.dll; \
ext-ms-win-rtcore-gdi-object-l1.dll; \
ext-ms-win-rtcore-ntuser-cursor-l1.dll; \
ext-ms-win-rtcore-ntuser-dc-access-l1.dll; \
ext-ms-win-rtcore-ntuser-syscolors-l1.dll; \
ext-ms-win-rtcore-ntuser-sysparams-l1.dll; \
ext-ms-win-shell-shell32-l1.dll; \
ext-ms-win-appmodel-shellexecute-l1.dll; \
ext-ms-win-gdi-internal-desktop-l1.dll; \
DLOAD_ERROR_HANDLER = kernelbase
# -------------------------------------
# Side-by-side Manifesting
# -------------------------------------

View file

@ -33,7 +33,15 @@ HRESULT _lookupCatalog(PCWSTR extensionName, std::vector<T>& vec) noexcept
{
vec.clear();
auto coinit = wil::CoInitializeEx(COINIT_MULTITHREADED);
T useInbox = { 0 };
useInbox.clsid = { 0 };
// CLSID of 0 will be sentinel to say "inbox console" or something.
// The UI displaying this information will have to go look up appropriate strings
// to convey that message.
vec.push_back(useInbox);
auto coinit = wil::CoInitializeEx(COINIT_APARTMENTTHREADED);
ComPtr<IAppExtensionCatalogStatics> catalogStatics;
RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_AppExtensions_AppExtensionCatalog).Get(), &catalogStatics));
@ -59,24 +67,34 @@ HRESULT _lookupCatalog(PCWSTR extensionName, std::vector<T>& vec) noexcept
ComPtr<IPackage> extensionPackage;
RETURN_IF_FAILED(extension->get_Package(&extensionPackage));
ComPtr<IPackage2> extensionPackage2;
RETURN_IF_FAILED(extensionPackage.As(&extensionPackage2));
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()));
RETURN_IF_FAILED(extensionPackage2->get_DisplayName(name.GetAddressOf()));
extensionMetadata.name = std::wstring{ name.GetRawBuffer(nullptr) };
// PackageId.Version
HString publisher;
RETURN_IF_FAILED(extensionPackageId->get_Publisher(publisher.GetAddressOf()));
RETURN_IF_FAILED(extensionPackage2->get_PublisherDisplayName(publisher.GetAddressOf()));
extensionMetadata.author = std::wstring{ publisher.GetRawBuffer(nullptr) };
HString pfn;
RETURN_IF_FAILED(extensionPackageId->get_FamilyName(pfn.GetAddressOf()));
extensionMetadata.pfn = std::wstring{ pfn.GetRawBuffer(nullptr) };
PackageVersion version;
RETURN_IF_FAILED(extensionPackageId->get_Version(&version));
extensionMetadata.version.major = version.Major;
extensionMetadata.version.minor = version.Minor;
extensionMetadata.version.build = version.Build;
extensionMetadata.version.revision = version.Revision;
// Fetch the custom properties XML out of the extension information
ComPtr<IAsyncOperation<IPropertySet*>> propertiesOperation;
RETURN_IF_FAILED(extension->GetExtensionPropertiesAsync(&propertiesOperation));
@ -149,23 +167,91 @@ try
}
CATCH_RETURN()
[[nodiscard]] HRESULT DelegationConfig::s_SetConsole(const DelegationConsole& console) noexcept
[[nodiscard]] HRESULT DelegationConfig::s_GetAvailablePackages(std::vector<DelegationPackage>& packages, DelegationPackage& defPackage) noexcept
try
{
return s_Set(DELEGATION_CONSOLE_KEY_NAME, console.clsid);
packages.clear();
std::vector<DelegationConsole> consoles;
RETURN_IF_FAILED(s_GetAvailableConsoles(consoles));
std::vector<DelegationTerminal> terminals;
RETURN_IF_FAILED(s_GetAvailableTerminals(terminals));
// TODO: I hate this algorithm (it's bad performance), but I couldn't
// find an AppModel interface that would let me look up all the extensions
// in one package.
for (auto& term : terminals)
{
for (auto& con : consoles)
{
if (term.IsFromSamePackage(con))
{
DelegationPackage pkg;
pkg.terminal = term;
pkg.console = con;
packages.push_back(pkg);
break;
}
}
}
// We should find at least one package.
RETURN_HR_IF(E_FAIL, packages.empty());
// We also find the default here while we have the list of available ones so
// we can return the opaque structure instead of the raw IID.
IID defCon;
RETURN_IF_FAILED(s_GetDefaultConsoleId(defCon));
IID defTerm;
RETURN_IF_FAILED(s_GetDefaultTerminalId(defTerm));
// The default one is the 0th one because that's supposed to be the inbox conhost one.
DelegationPackage chosenPackage = packages.at(0);
// Search through and find a package that matches. If we failed to match because
// it's torn across multiple or something not in the catalog, we'll offer the inbox conhost one.
for (auto& pkg : packages)
{
if (pkg.console.clsid == defCon && pkg.terminal.clsid == defTerm)
{
chosenPackage = pkg;
break;
}
}
defPackage = chosenPackage;
return S_OK;
}
CATCH_RETURN()
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultConsoleById(const IID& iid) noexcept
{
return s_Set(DELEGATION_CONSOLE_KEY_NAME, iid);
}
[[nodiscard]] HRESULT DelegationConfig::s_SetTerminal(const DelegationTerminal& terminal) noexcept
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultTerminalById(const IID& iid) noexcept
{
return s_Set(DELEGATION_TERMINAL_KEY_NAME, terminal.clsid);
return s_Set(DELEGATION_TERMINAL_KEY_NAME, iid);
}
[[nodiscard]] HRESULT DelegationConfig::s_GetConsole(IID& iid) noexcept
[[nodiscard]] HRESULT DelegationConfig::s_SetDefaultByPackage(const DelegationPackage& package) noexcept
{
RETURN_IF_FAILED(s_SetDefaultConsoleById(package.console.clsid));
RETURN_IF_FAILED(s_SetDefaultTerminalById(package.terminal.clsid));
return S_OK;
}
[[nodiscard]] HRESULT DelegationConfig::s_GetDefaultConsoleId(IID& iid) noexcept
{
iid = { 0 };
return s_Get(DELEGATION_CONSOLE_KEY_NAME, iid);
}
[[nodiscard]] HRESULT DelegationConfig::s_GetTerminal(IID& iid) noexcept
[[nodiscard]] HRESULT DelegationConfig::s_GetDefaultTerminalId(IID& iid) noexcept
{
iid = { 0 };
return s_Get(DELEGATION_TERMINAL_KEY_NAME, iid);
}
@ -192,7 +278,7 @@ CATCH_RETURN()
RETURN_NTSTATUS(result);
}
auto buffer = std::make_unique<wchar_t[]>(bytesNeeded / sizeof(wchar_t));
auto buffer = std::make_unique<wchar_t[]>(bytesNeeded / sizeof(wchar_t) + 1);
DWORD bytesUsed = 0;
@ -222,7 +308,7 @@ try
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_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;
}

View file

@ -18,11 +18,46 @@ Author(s):
class DelegationConfig
{
public:
struct PkgVersion
{
unsigned short major;
unsigned short minor;
unsigned short build;
unsigned short revision;
bool operator==(const PkgVersion& other) const
{
return major == other.major &&
minor == other.minor &&
build == other.build &&
revision == other.revision;
}
};
struct DelegationBase
{
CLSID clsid;
std::wstring name;
std::wstring author;
std::wstring pfn;
PkgVersion version;
bool IsFromSamePackage(const DelegationBase& other) const
{
return name == other.name &&
author == other.author &&
pfn == other.pfn &&
version == other.version;
}
bool operator==(const DelegationBase& other) const
{
return clsid == other.clsid &&
name == other.name &&
author == other.author &&
pfn == other.pfn &&
version == other.version;
}
};
struct DelegationConsole : public DelegationBase
@ -33,16 +68,32 @@ public:
{
};
struct DelegationPackage
{
DelegationConsole console;
DelegationTerminal terminal;
bool operator==(const DelegationPackage& other) const
{
return console == other.console &&
terminal == other.terminal;
}
};
[[nodiscard]] static HRESULT s_GetAvailablePackages(std::vector<DelegationPackage>& packages, DelegationPackage& default) noexcept;
[[nodiscard]] static HRESULT s_SetDefaultByPackage(const DelegationPackage& pkg) noexcept;
[[nodiscard]] static HRESULT s_GetDefaultConsoleId(IID& iid) noexcept;
[[nodiscard]] static HRESULT s_GetDefaultTerminalId(IID& iid) noexcept;
private:
[[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_SetDefaultConsoleById(const IID& iid) noexcept;
[[nodiscard]] static HRESULT s_SetDefaultTerminalById(const IID& iid) 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

@ -51,4 +51,7 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
</ItemGroup>
</Project>

View file

@ -138,6 +138,79 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleCloseObject(_In_ PCONSOLE_API_MSG pMessag
return pMessage;
}
// Routine Description:
// - Uses some information about current console state and
// the incoming process state and preferences to determine
// whether we should attempt to handoff to a registered console.
static bool _shouldAttemptHandoff(const Globals& globals,
const CONSOLE_INFORMATION& gci,
CONSOLE_API_CONNECTINFO& cac)
{
// This console is already initialized. Do not
// attempt handoff to another one.
// Note you can have a non-attach secondary connect for a child process
// that is supposed to be inheriting the existing console/window from the parent.
if (WI_IsFlagSet(gci.Flags, CONSOLE_INITIALIZED))
{
return false;
}
// If this is an AttachConsole message and not occuring
// because of a conclnt!ConsoleInitialize, do not handoff.
// ConsoleApp is FALSE for attach.
if (!cac.ConsoleApp)
{
return false;
}
// If it is a PTY session, do not attempt handoff.
if (globals.launchArgs.IsHeadless())
{
return false;
}
// If we do not have a registered handoff, do not attempt.
if (!globals.handoffConsoleClsid)
{
return false;
}
// If we're already a target for receiving another handoff,
// do not chain.
if (globals.handoffTarget)
{
return false;
}
// If the client was started with CREATE_NO_WINDOW to CreateProcess,
// this function will say that it does NOT deserve a visible window.
// Return false.
if (!ConsoleConnectionDeservesVisibleWindow(&cac))
{
return false;
}
// If the process is giving us explicit window show information, we need
// to look at which one it is.
if (WI_IsFlagSet(cac.ConsoleInfo.GetStartupFlags(), STARTF_USESHOWWINDOW))
{
switch (cac.ConsoleInfo.GetShowWindow())
{
// For all hide or minimize actions, do not hand off.
case SW_HIDE:
case SW_SHOWMINIMIZED:
case SW_MINIMIZE:
case SW_SHOWMINNOACTIVE:
case SW_FORCEMINIMIZE:
return false;
// Intentionally fall through for all others
// like maximize and show to hit the true below.
}
}
return true;
}
// Routine Description:
// - Used when a client application establishes an initial connection to this console server.
// - This is supposed to represent accounting for the process, making the appropriate handles, etc.
@ -165,12 +238,9 @@ 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...
// If we pass the tests...
// then attempt to delegate the startup to the registered replacement.
if (!Globals.launchArgs.IsHeadless() && Globals.handoffConsoleClsid && !Globals.handoffTarget && ConsoleConnectionDeservesVisibleWindow(&Cac))
if (_shouldAttemptHandoff(Globals, gci, Cac))
{
try
{