3909cc103a
[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
765 lines
25 KiB
C++
765 lines
25 KiB
C++
/*++
|
|
|
|
Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT license.
|
|
|
|
Module Name:
|
|
menu.c
|
|
|
|
Abstract:
|
|
This file implements the system menu management.
|
|
|
|
Author:
|
|
Therese Stowell (thereses) Jan-24-1992 (swiped from Win3.1)
|
|
|
|
Revision History:
|
|
Mike Griese (migrie) Oct-2016 - Move to OpenConsole project
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "conint.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
UINT gnCurrentPage;
|
|
|
|
#define SYSTEM_ROOT (L"%SystemRoot%")
|
|
#define SYSTEM_ROOT_LENGTH (sizeof(SYSTEM_ROOT) - sizeof(WCHAR))
|
|
|
|
void RecreateFontHandles(const HWND hWnd);
|
|
|
|
void UpdateItem(HWND hDlg, UINT item, UINT nNum)
|
|
{
|
|
SetDlgItemInt(hDlg, item, nNum, TRUE);
|
|
SendDlgItemMessage(hDlg, item, EM_SETSEL, 0, -1);
|
|
}
|
|
|
|
// Routine Description:
|
|
// Sends an EM_UNDO message. Typically used after some user data is determined to be invalid.
|
|
void Undo(HWND hControlWindow)
|
|
{
|
|
if (!InEM_UNDO)
|
|
{
|
|
InEM_UNDO = TRUE;
|
|
SendMessage(hControlWindow, EM_UNDO, 0, 0);
|
|
InEM_UNDO = FALSE;
|
|
}
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Validates a string in the TextItem with id=Item represents a number
|
|
BOOL CheckNum(HWND hDlg, UINT Item)
|
|
{
|
|
int i;
|
|
TCHAR szNum[5];
|
|
BOOL fSigned;
|
|
|
|
// The window position coordinates can be signed, nothing else.
|
|
if (Item == IDD_WINDOW_POSX || Item == IDD_WINDOW_POSY)
|
|
{
|
|
fSigned = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fSigned = FALSE;
|
|
}
|
|
|
|
GetDlgItemText(hDlg, Item, szNum, ARRAYSIZE(szNum));
|
|
for (i = 0; szNum[i]; i++)
|
|
{
|
|
if (!iswdigit(szNum[i]) && (!fSigned || i > 0 || szNum[i] != TEXT('-')))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void SaveConsoleSettingsIfNeeded(const HWND hwnd)
|
|
{
|
|
if (gpStateInfo->UpdateValues)
|
|
{
|
|
// If we're looking at the default font, clear the values before we save them
|
|
if ((gpStateInfo->FontFamily == DefaultFontFamily) &&
|
|
(gpStateInfo->FontSize.X == DefaultFontSize.X) &&
|
|
(gpStateInfo->FontSize.Y == DefaultFontSize.Y) &&
|
|
(gpStateInfo->FontWeight == FW_NORMAL) &&
|
|
(wcscmp(gpStateInfo->FaceName, DefaultFaceName) == 0))
|
|
{
|
|
gpStateInfo->FontFamily = 0;
|
|
gpStateInfo->FontSize.X = 0;
|
|
gpStateInfo->FontSize.Y = 0;
|
|
gpStateInfo->FontWeight = 0;
|
|
gpStateInfo->FaceName[0] = TEXT('\0');
|
|
}
|
|
|
|
if (g_defAppEnabled)
|
|
{
|
|
LOG_IF_FAILED(DelegationConfig::s_SetDefaultByPackage(g_selectedPackage));
|
|
}
|
|
|
|
if (gpStateInfo->LinkTitle != nullptr)
|
|
{
|
|
SetGlobalRegistryValues();
|
|
if (!NT_SUCCESS(ShortcutSerialization::s_SetLinkValues(gpStateInfo,
|
|
g_fEastAsianSystem,
|
|
g_fForceV2,
|
|
gpStateInfo->fIsV2Console)))
|
|
{
|
|
WCHAR szMessage[MAX_PATH + 100];
|
|
WCHAR awchBuffer[MAX_PATH] = { 0 };
|
|
STARTUPINFOW si;
|
|
|
|
// An error occurred try to save the link file, display a message box to that effect...
|
|
GetStartupInfoW(&si);
|
|
LoadStringW(ghInstance, IDS_LINKERROR, awchBuffer, ARRAYSIZE(awchBuffer));
|
|
StringCchPrintf(szMessage,
|
|
ARRAYSIZE(szMessage),
|
|
awchBuffer,
|
|
gpStateInfo->LinkTitle);
|
|
LoadStringW(ghInstance, IDS_LINKERRCAP, awchBuffer, ARRAYSIZE(awchBuffer));
|
|
|
|
MessageBoxW(hwnd,
|
|
szMessage,
|
|
awchBuffer,
|
|
MB_APPLMODAL | MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
|
|
}
|
|
else
|
|
{
|
|
// we're up to date, so mark ourselves as such (needed for "Apply" case)
|
|
gpStateInfo->UpdateValues = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetRegistryValues(gpStateInfo, gnCurrentPage);
|
|
|
|
// we're up to date, so mark ourselves as such (needed for "Apply" case)
|
|
gpStateInfo->UpdateValues = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EndDlgPage(const HWND hDlg, const BOOL fSaveNow)
|
|
{
|
|
HWND hParent;
|
|
HWND hTabCtrl;
|
|
|
|
/*
|
|
* If we've already made a decision, we're done
|
|
*/
|
|
if (gpStateInfo->UpdateValues)
|
|
{
|
|
SetDlgMsgResult(hDlg, PSN_APPLY, PSNRET_NOERROR);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Get the current page number
|
|
*/
|
|
hParent = GetParent(hDlg);
|
|
hTabCtrl = PropSheet_GetTabControl(hParent);
|
|
gnCurrentPage = TabCtrl_GetCurSel(hTabCtrl);
|
|
|
|
gpStateInfo->UpdateValues = TRUE;
|
|
|
|
SetDlgMsgResult(hDlg, PSN_APPLY, PSNRET_NOERROR);
|
|
|
|
if (fSaveNow)
|
|
{
|
|
// needed for "Apply" scenario
|
|
SaveConsoleSettingsIfNeeded(hDlg);
|
|
}
|
|
|
|
PropSheet_UnChanged(hDlg, 0);
|
|
}
|
|
|
|
#define TOOLTIP_MAXLENGTH (256)
|
|
void CreateAndAssociateToolTipToControl(const UINT dlgItem, const HWND hDlg, const UINT idsToolTip)
|
|
{
|
|
HWND hwndTooltip = CreateWindowEx(0 /*dwExtStyle*/,
|
|
TOOLTIPS_CLASS,
|
|
nullptr /*lpWindowName*/,
|
|
TTS_ALWAYSTIP,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
hDlg,
|
|
nullptr /*hMenu*/,
|
|
ghInstance,
|
|
nullptr /*lpParam*/);
|
|
|
|
if (hwndTooltip)
|
|
{
|
|
WCHAR szTooltip[TOOLTIP_MAXLENGTH] = { 0 };
|
|
if (LoadString(ghInstance, idsToolTip, szTooltip, ARRAYSIZE(szTooltip)) > 0)
|
|
{
|
|
TOOLINFO toolInfo = { 0 };
|
|
toolInfo.cbSize = sizeof(toolInfo);
|
|
toolInfo.hwnd = hDlg;
|
|
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
|
|
toolInfo.uId = (UINT_PTR)GetDlgItem(hDlg, dlgItem);
|
|
toolInfo.lpszText = szTooltip;
|
|
SendMessage(hwndTooltip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL UpdateStateInfo(HWND hDlg, UINT Item, int Value)
|
|
{
|
|
switch (Item)
|
|
{
|
|
case IDD_SCRBUF_WIDTH:
|
|
gpStateInfo->ScreenBufferSize.X = (SHORT)Value;
|
|
|
|
// If we're in V2 mode with wrap text on OR if the window is larger than the buffer, adjust the window to match.
|
|
if ((g_fForceV2 && gpStateInfo->fWrapText) || gpStateInfo->WindowSize.X > Value)
|
|
{
|
|
gpStateInfo->WindowSize.X = (SHORT)Value;
|
|
UpdateItem(hDlg, IDD_WINDOW_WIDTH, Value);
|
|
}
|
|
break;
|
|
case IDD_SCRBUF_HEIGHT:
|
|
gpStateInfo->ScreenBufferSize.Y = (SHORT)Value;
|
|
if (gpStateInfo->WindowSize.Y > Value)
|
|
{
|
|
gpStateInfo->WindowSize.Y = (SHORT)Value;
|
|
UpdateItem(hDlg, IDD_WINDOW_HEIGHT, Value);
|
|
}
|
|
break;
|
|
case IDD_WINDOW_WIDTH:
|
|
gpStateInfo->WindowSize.X = (SHORT)Value;
|
|
|
|
// If we're in V2 mode with wrap text on OR if the buffer is smaller than the window, adjust the buffer to match.
|
|
if ((g_fForceV2 && gpStateInfo->fWrapText) || gpStateInfo->ScreenBufferSize.X < Value)
|
|
{
|
|
gpStateInfo->ScreenBufferSize.X = (SHORT)Value;
|
|
UpdateItem(hDlg, IDD_SCRBUF_WIDTH, Value);
|
|
}
|
|
break;
|
|
case IDD_WINDOW_HEIGHT:
|
|
gpStateInfo->WindowSize.Y = (SHORT)Value;
|
|
if (gpStateInfo->ScreenBufferSize.Y < Value)
|
|
{
|
|
gpStateInfo->ScreenBufferSize.Y = (SHORT)Value;
|
|
UpdateItem(hDlg, IDD_SCRBUF_HEIGHT, Value);
|
|
}
|
|
break;
|
|
case IDD_WINDOW_POSX:
|
|
if (Value < 0)
|
|
{
|
|
gpStateInfo->WindowPosX = std::max(SHORT_MIN, Value);
|
|
}
|
|
else
|
|
{
|
|
gpStateInfo->WindowPosX = std::min(SHORT_MAX, Value);
|
|
}
|
|
break;
|
|
case IDD_WINDOW_POSY:
|
|
if (Value < 0)
|
|
{
|
|
gpStateInfo->WindowPosY = std::max(SHORT_MIN, Value);
|
|
}
|
|
else
|
|
{
|
|
gpStateInfo->WindowPosY = std::min(SHORT_MAX, Value);
|
|
}
|
|
break;
|
|
case IDD_AUTO_POSITION:
|
|
gpStateInfo->AutoPosition = Value;
|
|
break;
|
|
case IDD_COLOR_SCREEN_TEXT:
|
|
gpStateInfo->ScreenAttributes =
|
|
(gpStateInfo->ScreenAttributes & 0xF0) |
|
|
(Value & 0x0F);
|
|
break;
|
|
case IDD_COLOR_SCREEN_BKGND:
|
|
gpStateInfo->ScreenAttributes =
|
|
(gpStateInfo->ScreenAttributes & 0x0F) |
|
|
(WORD)(Value << 4);
|
|
break;
|
|
case IDD_COLOR_POPUP_TEXT:
|
|
gpStateInfo->PopupAttributes =
|
|
(gpStateInfo->PopupAttributes & 0xF0) |
|
|
(Value & 0x0F);
|
|
break;
|
|
case IDD_COLOR_POPUP_BKGND:
|
|
gpStateInfo->PopupAttributes =
|
|
(gpStateInfo->PopupAttributes & 0x0F) |
|
|
(WORD)(Value << 4);
|
|
break;
|
|
case IDD_COLOR_1:
|
|
case IDD_COLOR_2:
|
|
case IDD_COLOR_3:
|
|
case IDD_COLOR_4:
|
|
case IDD_COLOR_5:
|
|
case IDD_COLOR_6:
|
|
case IDD_COLOR_7:
|
|
case IDD_COLOR_8:
|
|
case IDD_COLOR_9:
|
|
case IDD_COLOR_10:
|
|
case IDD_COLOR_11:
|
|
case IDD_COLOR_12:
|
|
case IDD_COLOR_13:
|
|
case IDD_COLOR_14:
|
|
case IDD_COLOR_15:
|
|
case IDD_COLOR_16:
|
|
gpStateInfo->ColorTable[Item - IDD_COLOR_1] = Value;
|
|
break;
|
|
case IDD_LANGUAGELIST:
|
|
/*
|
|
* Value is a code page
|
|
*/
|
|
gpStateInfo->CodePage = Value;
|
|
break;
|
|
case IDD_QUICKEDIT:
|
|
gpStateInfo->QuickEdit = Value;
|
|
break;
|
|
case IDD_INSERT:
|
|
gpStateInfo->InsertMode = Value;
|
|
break;
|
|
case IDD_HISTORY_SIZE:
|
|
gpStateInfo->HistoryBufferSize = std::max(Value, 1);
|
|
break;
|
|
case IDD_HISTORY_NUM:
|
|
gpStateInfo->NumberOfHistoryBuffers = std::max(Value, 1);
|
|
break;
|
|
case IDD_HISTORY_NODUP:
|
|
gpStateInfo->HistoryNoDup = Value;
|
|
break;
|
|
case IDD_CURSOR_SMALL:
|
|
gpStateInfo->CursorSize = 25;
|
|
// Set the cursor to legacy style
|
|
gpStateInfo->CursorType = 0;
|
|
// Check the legacy radio button on the terminal page
|
|
if (g_hTerminalDlg != INVALID_HANDLE_VALUE)
|
|
{
|
|
CheckRadioButton(g_hTerminalDlg,
|
|
IDD_TERMINAL_LEGACY_CURSOR,
|
|
IDD_TERMINAL_SOLIDBOX,
|
|
IDD_TERMINAL_LEGACY_CURSOR);
|
|
}
|
|
|
|
break;
|
|
case IDD_CURSOR_MEDIUM:
|
|
gpStateInfo->CursorSize = 50;
|
|
// Set the cursor to legacy style
|
|
gpStateInfo->CursorType = 0;
|
|
// Check the legacy radio button on the terminal page
|
|
if (g_hTerminalDlg != INVALID_HANDLE_VALUE)
|
|
{
|
|
CheckRadioButton(g_hTerminalDlg,
|
|
IDD_TERMINAL_LEGACY_CURSOR,
|
|
IDD_TERMINAL_SOLIDBOX,
|
|
IDD_TERMINAL_LEGACY_CURSOR);
|
|
}
|
|
|
|
break;
|
|
case IDD_CURSOR_LARGE:
|
|
gpStateInfo->CursorSize = 100;
|
|
// Set the cursor to legacy style
|
|
gpStateInfo->CursorType = 0;
|
|
// Check the legacy radio button on the terminal page
|
|
if (g_hTerminalDlg != INVALID_HANDLE_VALUE)
|
|
{
|
|
CheckRadioButton(g_hTerminalDlg,
|
|
IDD_TERMINAL_LEGACY_CURSOR,
|
|
IDD_TERMINAL_SOLIDBOX,
|
|
IDD_TERMINAL_LEGACY_CURSOR);
|
|
}
|
|
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Copied as a subset of open/src/host/srvinit.cpp's TranslateConsoleTitle
|
|
// Routine Description:
|
|
// - This routine translates path characters into '_' characters because the NT registry apis do not allow the creation of keys with
|
|
// names that contain path characters. It also converts absolute paths into %SystemRoot% relative ones. As an example, if both behaviors were
|
|
// specified it would convert a title like C:\WINNT\System32\cmd.exe to %SystemRoot%_System32_cmd.exe.
|
|
// Arguments:
|
|
// - ConsoleTitle - Pointer to string to translate.
|
|
// Return Value:
|
|
// - Pointer to translated title or nullptr.
|
|
// Note:
|
|
// - This routine allocates a buffer that must be freed.
|
|
PWSTR TranslateConsoleTitle(_In_ PCWSTR pwszConsoleTitle)
|
|
{
|
|
bool fUnexpand = true;
|
|
bool fSubstitute = true;
|
|
|
|
LPWSTR Tmp = nullptr;
|
|
|
|
size_t cbConsoleTitle;
|
|
size_t cbSystemRoot;
|
|
|
|
LPWSTR pwszSysRoot = new (std::nothrow) wchar_t[MAX_PATH];
|
|
if (nullptr != pwszSysRoot)
|
|
{
|
|
if (0 != GetWindowsDirectoryW(pwszSysRoot, MAX_PATH))
|
|
{
|
|
if (SUCCEEDED(StringCbLengthW(pwszConsoleTitle, STRSAFE_MAX_CCH, &cbConsoleTitle)) &&
|
|
SUCCEEDED(StringCbLengthW(pwszSysRoot, MAX_PATH, &cbSystemRoot)))
|
|
{
|
|
int const cchSystemRoot = (int)(cbSystemRoot / sizeof(WCHAR));
|
|
int const cchConsoleTitle = (int)(cbConsoleTitle / sizeof(WCHAR));
|
|
cbConsoleTitle += sizeof(WCHAR); // account for nullptr terminator
|
|
|
|
if (fUnexpand &&
|
|
cchConsoleTitle >= cchSystemRoot &&
|
|
#pragma prefast(suppress : 26018, "We've guaranteed that cchSystemRoot is equal to or smaller than cchConsoleTitle in size.")
|
|
(CSTR_EQUAL == CompareStringOrdinal(pwszConsoleTitle, cchSystemRoot, pwszSysRoot, cchSystemRoot, TRUE)))
|
|
{
|
|
cbConsoleTitle -= cbSystemRoot;
|
|
pwszConsoleTitle += cchSystemRoot;
|
|
cbSystemRoot = SYSTEM_ROOT_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
cbSystemRoot = 0;
|
|
}
|
|
|
|
LPWSTR TranslatedConsoleTitle;
|
|
// This has to be a HeapAlloc, because it gets HeapFree'd later
|
|
Tmp = TranslatedConsoleTitle = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (cchSystemRoot + cchConsoleTitle) * sizeof(WCHAR));
|
|
|
|
if (TranslatedConsoleTitle == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
memmove(TranslatedConsoleTitle, SYSTEM_ROOT, cbSystemRoot);
|
|
TranslatedConsoleTitle += (cbSystemRoot / sizeof(WCHAR)); // skip by characters -- not bytes
|
|
|
|
for (UINT i = 0; i < cbConsoleTitle; i += sizeof(WCHAR))
|
|
{
|
|
#pragma prefast(suppress : 26018, "We are reading the null portion of the buffer on purpose and will escape on reaching it below.")
|
|
if (fSubstitute && *pwszConsoleTitle == '\\')
|
|
{
|
|
#pragma prefast(suppress : 26019, "Console title must contain system root if this path was followed.")
|
|
*TranslatedConsoleTitle++ = (WCHAR)'_';
|
|
}
|
|
else
|
|
{
|
|
*TranslatedConsoleTitle++ = *pwszConsoleTitle;
|
|
if (*pwszConsoleTitle == L'\0')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
pwszConsoleTitle++;
|
|
}
|
|
}
|
|
}
|
|
delete[] pwszSysRoot;
|
|
}
|
|
|
|
return Tmp;
|
|
}
|
|
|
|
// For use by property sheets when added to file props dialog -- maintain refcount of each page and release things we've
|
|
// registered when we hit 0. Needed because the lifetime of the property sheets isn't tied to the lifetime of our
|
|
// IShellPropSheetExt object.
|
|
UINT CALLBACK PropSheetPageProc(_In_ HWND hWnd, _In_ UINT uMsg, _Inout_ LPPROPSHEETPAGE /*ppsp*/)
|
|
{
|
|
static UINT cRefs = 0;
|
|
switch (uMsg)
|
|
{
|
|
case PSPCB_ADDREF:
|
|
{
|
|
cRefs++;
|
|
break;
|
|
}
|
|
|
|
case PSPCB_RELEASE:
|
|
{
|
|
cRefs--;
|
|
if (cRefs == 0)
|
|
{
|
|
if (gpStateInfo->UpdateValues)
|
|
{
|
|
// only persist settings if they've changed
|
|
SaveConsoleSettingsIfNeeded(hWnd);
|
|
}
|
|
|
|
UninitializeConsoleState();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
BOOL PopulatePropSheetPageArray(_Out_writes_(cPsps) PROPSHEETPAGE* pPsp, const size_t cPsps, const BOOL fRegisterCallbacks)
|
|
{
|
|
BOOL fRet = (cPsps == NUMBER_OF_PAGES);
|
|
if (fRet)
|
|
{
|
|
// This has been validated above. OACR is being silly. Restate it so it can see the condition.
|
|
__analysis_assume(cPsps == NUMBER_OF_PAGES);
|
|
|
|
PROPSHEETPAGE* const pOptionsPage = &(pPsp[OPTIONS_PAGE_INDEX]);
|
|
PROPSHEETPAGE* const pFontPage = &(pPsp[FONT_PAGE_INDEX]);
|
|
PROPSHEETPAGE* const pLayoutPage = &(pPsp[LAYOUT_PAGE_INDEX]);
|
|
PROPSHEETPAGE* const pColorsPage = &(pPsp[COLORS_PAGE_INDEX]);
|
|
PROPSHEETPAGE* const pTerminalPage = &(pPsp[TERMINAL_PAGE_INDEX]);
|
|
|
|
pOptionsPage->dwSize = sizeof(PROPSHEETPAGE);
|
|
pOptionsPage->hInstance = ghInstance;
|
|
if (g_fIsComCtlV6Present)
|
|
{
|
|
pOptionsPage->pszTemplate = (gpStateInfo->Defaults) ? MAKEINTRESOURCE(DID_SETTINGS) : MAKEINTRESOURCE(DID_SETTINGS2);
|
|
}
|
|
else
|
|
{
|
|
pOptionsPage->pszTemplate = (gpStateInfo->Defaults) ? MAKEINTRESOURCE(DID_SETTINGS_COMCTL5) : MAKEINTRESOURCE(DID_SETTINGS2_COMCTL5);
|
|
}
|
|
pOptionsPage->pfnDlgProc = SettingsDlgProc;
|
|
pOptionsPage->lParam = OPTIONS_PAGE_INDEX;
|
|
pOptionsPage->dwFlags = PSP_DEFAULT;
|
|
|
|
pFontPage->dwSize = sizeof(PROPSHEETPAGE);
|
|
pFontPage->hInstance = ghInstance;
|
|
pFontPage->pszTemplate = MAKEINTRESOURCE(DID_FONTDLG);
|
|
pFontPage->pfnDlgProc = FontDlgProc;
|
|
pFontPage->lParam = FONT_PAGE_INDEX;
|
|
pOptionsPage->dwFlags = PSP_DEFAULT;
|
|
|
|
pLayoutPage->dwSize = sizeof(PROPSHEETPAGE);
|
|
pLayoutPage->hInstance = ghInstance;
|
|
pLayoutPage->pszTemplate = MAKEINTRESOURCE(DID_SCRBUFSIZE);
|
|
pLayoutPage->pfnDlgProc = ScreenSizeDlgProc;
|
|
pLayoutPage->lParam = LAYOUT_PAGE_INDEX;
|
|
pOptionsPage->dwFlags = PSP_DEFAULT;
|
|
|
|
pColorsPage->dwSize = sizeof(PROPSHEETPAGE);
|
|
pColorsPage->hInstance = ghInstance;
|
|
pColorsPage->pszTemplate = MAKEINTRESOURCE(DID_COLOR);
|
|
pColorsPage->pfnDlgProc = ColorDlgProc;
|
|
pColorsPage->lParam = COLORS_PAGE_INDEX;
|
|
pOptionsPage->dwFlags = PSP_DEFAULT;
|
|
if (g_fForceV2)
|
|
{
|
|
pTerminalPage->dwSize = sizeof(PROPSHEETPAGE);
|
|
pTerminalPage->hInstance = ghInstance;
|
|
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;
|
|
}
|
|
|
|
// Register callbacks if requested (used for file property sheet purposes)
|
|
if (fRegisterCallbacks)
|
|
{
|
|
for (UINT iPage = 0; iPage < cPsps; iPage++)
|
|
{
|
|
pPsp[iPage].pfnCallback = &PropSheetPageProc;
|
|
pPsp[iPage].dwFlags |= PSP_USECALLBACK;
|
|
}
|
|
}
|
|
|
|
fRet = TRUE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
// Routine Description:
|
|
// - Creates the property sheet to change console settings.
|
|
INT_PTR ConsolePropertySheet(__in HWND hWnd, __in PCONSOLE_STATE_INFO pStateInfo)
|
|
{
|
|
PROPSHEETPAGE psp[NUMBER_OF_PAGES];
|
|
PROPSHEETHEADER psh;
|
|
INT_PTR Result = IDCANCEL;
|
|
WCHAR awchBuffer[MAX_PATH] = { 0 };
|
|
|
|
gpStateInfo = pStateInfo;
|
|
|
|
// In v2 console, consider this an East Asian system if we're currently in a CJK charset. In v1, look at the system codepage.
|
|
if (gpStateInfo->fIsV2Console)
|
|
{
|
|
g_fEastAsianSystem = IS_ANY_DBCS_CHARSET(CodePageToCharSet(gpStateInfo->CodePage));
|
|
}
|
|
else
|
|
{
|
|
g_fEastAsianSystem = IsEastAsianCP(GetOEMCP());
|
|
}
|
|
|
|
//
|
|
// Initialize the state information.
|
|
//
|
|
if (gpStateInfo->Defaults)
|
|
{
|
|
InitRegistryValues(pStateInfo);
|
|
GetRegistryValues(pStateInfo);
|
|
}
|
|
|
|
//
|
|
// Initialize the font cache and current font index
|
|
//
|
|
|
|
InitializeFonts();
|
|
g_currentFontIndex = FindCreateFont(gpStateInfo->FontFamily,
|
|
gpStateInfo->FaceName,
|
|
gpStateInfo->FontSize,
|
|
gpStateInfo->FontWeight,
|
|
gpStateInfo->CodePage);
|
|
|
|
// 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
|
|
//
|
|
|
|
gnCurrentPage = GetRegistryValues(nullptr);
|
|
|
|
//
|
|
// Initialize the property sheet structures
|
|
//
|
|
|
|
RtlZeroMemory(psp, sizeof(psp));
|
|
PopulatePropSheetPageArray(psp, ARRAYSIZE(psp), FALSE /*fRegisterCallbacks*/);
|
|
|
|
psh.dwSize = sizeof(PROPSHEETHEADER);
|
|
psh.dwFlags = PSH_PROPTITLE | PSH_USEHICON | PSH_PROPSHEETPAGE |
|
|
PSH_NOAPPLYNOW | PSH_USECALLBACK | PSH_NOCONTEXTHELP;
|
|
if (gpStateInfo->Defaults)
|
|
{
|
|
LoadString(ghInstance, IDS_TITLE, awchBuffer, ARRAYSIZE(awchBuffer));
|
|
}
|
|
else
|
|
{
|
|
awchBuffer[0] = L'"';
|
|
ExpandEnvironmentStrings(gpStateInfo->OriginalTitle,
|
|
&awchBuffer[1],
|
|
ARRAYSIZE(awchBuffer) - 2);
|
|
StringCchCat(awchBuffer, ARRAYSIZE(awchBuffer), TEXT("\""));
|
|
gpStateInfo->OriginalTitle = TranslateConsoleTitle(gpStateInfo->OriginalTitle);
|
|
}
|
|
|
|
psh.hwndParent = hWnd;
|
|
psh.hIcon = gpStateInfo->hIcon;
|
|
psh.hInstance = ghInstance;
|
|
psh.pszCaption = awchBuffer;
|
|
psh.nPages = g_fForceV2 ? NUMBER_OF_PAGES : V1_NUMBER_OF_PAGES;
|
|
psh.nStartPage = std::min<UINT>(gnCurrentPage, ARRAYSIZE(psp));
|
|
psh.ppsp = psp;
|
|
psh.pfnCallback = nullptr;
|
|
|
|
//
|
|
// Create the property sheet
|
|
//
|
|
|
|
Result = PropertySheet(&psh);
|
|
|
|
//
|
|
// Save our changes to the registry
|
|
//
|
|
const BOOL fUpdatedValues = gpStateInfo->UpdateValues;
|
|
SaveConsoleSettingsIfNeeded(hWnd);
|
|
gpStateInfo->UpdateValues = fUpdatedValues;
|
|
|
|
if (!gpStateInfo->Defaults)
|
|
{
|
|
if (gpStateInfo->OriginalTitle != nullptr)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, gpStateInfo->OriginalTitle);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Destroy the font cache.
|
|
//
|
|
DestroyFonts();
|
|
|
|
return Result;
|
|
}
|
|
|
|
void RegisterClasses(HINSTANCE hModule)
|
|
{
|
|
WNDCLASS wc;
|
|
wc.lpszClassName = TEXT("SimpleColor");
|
|
wc.hInstance = hModule;
|
|
wc.lpfnWndProc = SimpleColorControlProc;
|
|
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
wc.hIcon = nullptr;
|
|
wc.lpszMenuName = nullptr;
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
RegisterClass(&wc);
|
|
|
|
wc.lpszClassName = TEXT("ColorTableColor");
|
|
wc.hInstance = hModule;
|
|
wc.lpfnWndProc = ColorTableControlProc;
|
|
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
wc.hIcon = nullptr;
|
|
wc.lpszMenuName = nullptr;
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
RegisterClass(&wc);
|
|
|
|
wc.lpszClassName = TEXT("WOAWinPreview");
|
|
wc.lpfnWndProc = PreviewWndProc;
|
|
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
|
|
wc.style = 0;
|
|
RegisterClass(&wc);
|
|
|
|
wc.lpszClassName = TEXT("WOAFontPreview");
|
|
wc.lpfnWndProc = FontPreviewWndProc;
|
|
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
wc.style = 0;
|
|
RegisterClass(&wc);
|
|
}
|
|
|
|
void UnregisterClasses(HINSTANCE hModule)
|
|
{
|
|
UnregisterClass(TEXT("cpColor"), hModule);
|
|
UnregisterClass(TEXT("WOAWinPreview"), hModule);
|
|
UnregisterClass(TEXT("WOAFontPreview"), hModule);
|
|
}
|
|
|
|
[[nodiscard]] HRESULT FindFontAndUpdateState()
|
|
{
|
|
g_currentFontIndex = FindCreateFont(gpStateInfo->FontFamily,
|
|
gpStateInfo->FaceName,
|
|
gpStateInfo->FontSize,
|
|
gpStateInfo->FontWeight,
|
|
gpStateInfo->CodePage);
|
|
|
|
gpStateInfo->FontFamily = FontInfo[g_currentFontIndex].Family;
|
|
gpStateInfo->FontSize = FontInfo[g_currentFontIndex].Size;
|
|
gpStateInfo->FontWeight = FontInfo[g_currentFontIndex].Weight;
|
|
return StringCchCopyW(gpStateInfo->FaceName, ARRAYSIZE(gpStateInfo->FaceName), FontInfo[g_currentFontIndex].FaceName);
|
|
}
|