Compare commits

...

8 Commits

Author SHA1 Message Date
Dustin L. Howett
ece1296397 HAX: wer 2023-02-01 21:12:56 -06:00
Dustin L. Howett
8b84e9165f Pop up a dialog box when Terminal blows up 2023-01-29 22:19:41 -06:00
Dustin L. Howett
ef107fe471 Allow AppHost to throw 2023-01-29 22:18:34 -06:00
Dustin L. Howett
6770c8fa81 Allow resource loaders to throw 2023-01-29 22:18:20 -06:00
Dustin L. Howett
f54b5a93a5 Remove NPE in WindowManager 2023-01-29 22:17:45 -06:00
James Holderness
282c583731 Make all console output modes more strictly buffer state (#14735)
The original console output modes were considered attributes of the
buffer, while later additions were treated as global state, and yet both
were accessed via the same buffer-based API. This could result in the
reported modes being out of sync with the way the system was actually
behaving, and a call to `SetConsoleMode` without updating anything could
still trigger unpredictable changes in behavior.

This PR attempts to address that problem by making all modes part of the
buffer state, and giving them predictable default values.

While this won't solve all the tmux layout-breaking issues in #6987, it
does at least fix one case which was the result of an unexpected change
in the `DISABLE_NEWLINE_AUTO_RETURN` mode.

All access to the output modes is now done via the `OutputMode` field in
`SCREEN_INFORMATION`. The fields that were tracking global state in the
`Settings` class (`_fAutoReturnOnNewline` and  `_fRenderGridWorldwide`)
have now been removed.

We still have a global `_dwVirtTermLevel` field, though, but that now
serves as a default value for the `ENABLE_VIRTUAL_TERMINAL_PROCESSING`
mode when creating a new buffer. It's enabled for conpty mode, and when
the VT level in the registry is not 0. That default doesn't change.

For the VT alternate buffer, things works slightly differently, since
there is an expectation that VT modes are global. So when creating an
alt buffer, we copy the current modes from the main buffer, and when
it's closed, we copy them back again.

## Validation Steps Performed

I've manually confirmed that this fixes the problem described in issue
#14690. I've also added a basic feature test that confirms the modes are
initialized as expected when creating new buffers, and changes to the
modes in one buffer do not impact any other buffers.

Closes #14690
2023-01-27 20:38:37 +00:00
Dustin L. Howett
fc960e3327 Generalize OpenConsoleProxy's HybridCRT logic (#14733)
This pull request moves the Hybrid CRT logic out of the Host.Proxy
project and makes it available for all other projects in our solution.
2023-01-27 19:17:30 +00:00
Dustin L. Howett
6a610334af When generating a stacked changelog, note which branch/es contain a commit (#14728)
New-TerminalStackedChangelog used to generate logs that looked like this:

```
* [3] A commit that was seen 3 times
* A commit that was only seen once
* [2] Some other commit
```

Now it will generate logs that look like this:

```
   / base..branch-1
   |/ base..branch-2
   ||/ base..branch-3
* [XXX] A commit that was seen 3 times
* [ X ] A commit that was only seen once
* [XX ] Some other commit
```

This format is more expressive, as it indicates _which branches_ contain which commits.

As a reminder, my release note writing style starts with a stacked changelog. It's how I tell (1) which commits are in the new preview release only, (2) which commits are in the new preview and the new stable release and (3) which commits were already released in a previous stable release.

Changes from 1 get included in the new changelog, changes from 2 get included in both and changes from 3 get deleted because they have already been released.
2023-01-25 10:52:11 -08:00
28 changed files with 315 additions and 139 deletions

View File

@@ -14,6 +14,7 @@
<UseWmXml>true</UseWmXml>
<ConfigurationType>Application</ConfigurationType>
<OpenConsoleCppWinRTProject>true</OpenConsoleCppWinRTProject>
<EnableHybridCRT>false</EnableHybridCRT> <!-- C++/CLI projects can't deal -->
<!--
These two properties are very important!

View File

@@ -60,4 +60,4 @@
<AdditionalDependencies>Uiautomationcore.lib;onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
</Project>
</Project>

View File

@@ -68,7 +68,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void WindowManager::SignalClose()
{
if (_monarch)
if (_monarch && _peasant)
{
try
{

View File

@@ -77,7 +77,6 @@ static void EnsureAllResourcesArePresent(const ScopedResourceLoader& loader)
#endif
static ScopedResourceLoader GetLibraryResourceLoader()
try
{
ScopedResourceLoader loader{ g_WinRTUtilsLibraryResourceScope };
#ifdef _DEBUG
@@ -85,20 +84,15 @@ try
#endif
return loader;
}
CATCH_FAIL_FAST()
winrt::hstring GetLibraryResourceString(const std::wstring_view key)
try
{
static auto loader{ GetLibraryResourceLoader() };
return loader.GetLocalizedString(key);
}
CATCH_FAIL_FAST()
bool HasLibraryResourceWithName(const std::wstring_view key)
try
{
static auto loader{ GetLibraryResourceLoader() };
return loader.HasResourceWithName(key);
}
CATCH_FAIL_FAST()

View File

@@ -28,7 +28,7 @@ using namespace std::chrono_literals;
// "If the high-order bit is 1, the key is down; otherwise, it is up."
static constexpr short KeyPressed{ gsl::narrow_cast<short>(0x8000) };
AppHost::AppHost() noexcept :
AppHost::AppHost() :
_app{},
_windowManager{},
_logic{ nullptr }, // don't make one, we're going to take a ref on app's

View File

@@ -9,7 +9,7 @@
class AppHost
{
public:
AppHost() noexcept;
AppHost();
virtual ~AppHost();
void AppTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, winrt::hstring newTitle);

View File

@@ -0,0 +1,81 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "resource.h"
#include <WerApi.h>
typedef wil::unique_any<HREPORT, decltype(&WerReportCloseHandle), WerReportCloseHandle> unique_wer_report;
struct ErrorDialogContext
{
HRESULT hr;
std::wstring message;
HFONT font{ nullptr };
~ErrorDialogContext()
{
if (font)
{
DeleteObject(font);
}
}
};
static LRESULT CALLBACK ErrDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
// We've passed in the pointer to an error dialog context using DialogBoxParam
ErrorDialogContext* ctx{ reinterpret_cast<ErrorDialogContext*>(lParam) };
SetWindowLongPtrW(hDlg, DWLP_USER, reinterpret_cast<LONG_PTR>(ctx));
HWND editControl{ GetDlgItem(hDlg, IDC_ERRVALUE) };
const auto message{ std::format(L"HR 0x{0:08x}\r\n{1}", static_cast<unsigned int>(ctx->hr), ctx->message) };
SetWindowTextW(editControl, message.c_str());
HFONT& font{ ctx->font };
const auto fontHeight{ -MulDiv(10, GetDpiForWindow(hDlg), 72) };
font = CreateFontW(fontHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE | FIXED_PITCH, L"Cascadia Mono");
if (!font)
{
font = CreateFontW(fontHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE | FIXED_PITCH, L"Consolas");
}
// Context takes ownership of font and deletes it later
SendMessageW(editControl, WM_SETFONT, reinterpret_cast<WPARAM>(font), 0);
break;
}
case WM_DESTROY:
{
ErrorDialogContext* ctx{ reinterpret_cast<ErrorDialogContext*>(GetWindowLongPtrW(hDlg, DWLP_USER)) };
delete ctx;
break;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hDlg, TRUE);
return TRUE;
}
}
}
return FALSE;
}
void DisplayErrorDialogBlockingAndReport(const HRESULT hr, const std::wstring_view message)
{
auto ctx = new ErrorDialogContext{ hr, std::wstring{ message } };
DialogBoxParamW(nullptr, MAKEINTRESOURCEW(IDD_ERRDIALOG), nullptr, ErrDlgProc, reinterpret_cast<LPARAM>(ctx));
unique_wer_report errorReport;
WerReportCreate(L"AppCrash", WerReportApplicationCrash, nullptr, errorReport.put());
WerReportAddDump(errorReport.get(), GetCurrentProcess(), nullptr, WerDumpTypeMiniDump, nullptr, nullptr, 0);
WerReportSubmit(errorReport.get(), WerConsentNotAsked, 0, nullptr);
TerminateProcess(GetCurrentProcess(), 1);
}

View File

@@ -0,0 +1,2 @@
void DisplayErrorDialogBlockingAndReport(const HRESULT hr, const std::wstring_view message);

View File

@@ -68,6 +68,23 @@ IDI_APPICON_HC_WHITE ICON "..\\..\\..\\res\\terminal\\imag
#endif
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ERRDIALOG DIALOGEX 0, 0, 310, 177
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 10, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,253,156,50,14
ICON 32513,IDC_STATIC,7,7,20,20
LTEXT "Windows Terminal has encountered an error and must exit.",IDC_STATIC,31,7,272,32
EDITTEXT IDC_ERRVALUE,7,31,296,121,ES_MULTILINE | ES_READONLY
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table

View File

@@ -38,7 +38,7 @@
<AdditionalIncludeDirectories>$(OpenConsoleDir)\src\inc;$(OpenConsoleDir)\dep;$(OpenConsoleDir)\dep\Console;$(OpenConsoleDir)\dep\Win32K;$(OpenConsoleDir)\dep\gsl\include;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>gdi32.lib;dwmapi.lib;Shcore.lib;UxTheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>wer.lib;gdi32.lib;dwmapi.lib;Shcore.lib;UxTheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<PropertyGroup>
@@ -68,6 +68,7 @@
<ClCompile Include="NotificationIcon.cpp" />
<ClCompile Include="VirtualDesktopUtils.cpp" />
<ClCompile Include="icon.cpp" />
<ClCompile Include="ErrorDialog.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="WindowsTerminal.rc" />

View File

@@ -6,6 +6,8 @@
#include "resource.h"
#include "../types/inc/User32Utils.hpp"
#include <WilErrorReporting.h>
#include <winrt/Windows.ApplicationModel.Core.h>
#include "ErrorDialog.h"
using namespace winrt;
using namespace winrt::Windows::UI;
@@ -127,25 +129,65 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
// doing that, we can safely init as STA before any WinRT dispatches.
winrt::init_apartment(winrt::apartment_type::single_threaded);
// Create the AppHost object, which will create both the window and the
// Terminal App. This MUST BE constructed before the Xaml manager as TermApp
// provides an implementation of Windows.UI.Xaml.Application.
AppHost host;
if (!host.HasWindow())
auto unhandledErrorRevoker{
winrt::Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected(winrt::auto_revoke, [](auto&&...) {
winrt::com_ptr<IRestrictedErrorInfo> restrictedErrorInfo;
if (SUCCEEDED(GetRestrictedErrorInfo(restrictedErrorInfo.put())) && restrictedErrorInfo)
{
wil::unique_bstr description, restrictedDescription, unused;
HRESULT hr;
if (SUCCEEDED(restrictedErrorInfo->GetErrorDetails(description.put(), &hr, restrictedDescription.put(), unused.put())))
{
DisplayErrorDialogBlockingAndReport(hr, restrictedDescription.get());
}
}
})
};
std::optional<AppHost> possiblyAppHost{ std::nullopt };
try
{
// If we were told to not have a window, exit early. Make sure to use
// ExitProcess to die here. If you try just `return 0`, then
// the XAML app host will crash during teardown. ExitProcess avoids
// that.
ExitProcess(0);
// Create the AppHost object, which will create both the window and the
// Terminal App. This MUST BE constructed before the Xaml manager as TermApp
// provides an implementation of Windows.UI.Xaml.Application.
possiblyAppHost.emplace();
if (!possiblyAppHost->HasWindow())
{
// If we were told to not have a window, exit early. Make sure to use
// ExitProcess to die here. If you try just `return 0`, then
// the XAML app host will crash during teardown. ExitProcess avoids
// that.
ExitProcess(0);
}
// Initialize the xaml content. This must be called AFTER the
// WindowsXamlManager is initialized.
possiblyAppHost->Initialize();
}
catch (const std::exception& e)
{
const auto wideErrorMessage{ til::u8u16(e.what()) };
DisplayErrorDialogBlockingAndReport(E_FAIL, wideErrorMessage);
}
catch (const winrt::hresult_error& e)
{
DisplayErrorDialogBlockingAndReport(e.code(), e.message());
}
catch (...)
{
DisplayErrorDialogBlockingAndReport(E_FAIL, L"LOL");
}
// Initialize the xaml content. This must be called AFTER the
// WindowsXamlManager is initialized.
host.Initialize();
AppHost& host{ *possiblyAppHost };
MSG message;
if (!Feature_ReportErrorsThroughoutAppLifetime::IsEnabled())
{
// Disengage error reporting after XAML starts up.
unhandledErrorRevoker.revoke();
}
while (GetMessage(&message, nullptr, 0, 0))
{
// GH#638 (Pressing F7 brings up both the history AND a caret browsing message)

View File

@@ -15,6 +15,10 @@
#define IDS_ARM_ARCHITECTURE 114
#define IDS_UNKNOWN_ARCHITECTURE 115
#define IDD_ERRDIALOG 129
#define IDC_ERRVALUE 1001
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED

View File

@@ -4,6 +4,42 @@
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
</ItemGroup>
<!--
The Hybrid CRT model statically links the runtime and STL and dynamically
links the UCRT instead of the VC++ CRT. The UCRT ships with Windows.
WinAppSDK asserts that this is "supported according to the CRT maintainer."
This must come before Microsoft.Cpp.targets because it manipulates ClCompile.RuntimeLibrary.
-->
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and '$(Configuration)'=='Debug'">
<ClCompile>
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and '$(Configuration)'=='Release'">
<ClCompile>
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ItemDefinitionGroup>

View File

@@ -28,6 +28,7 @@
<AppContainerApplication>true</AppContainerApplication>
<WindowsStoreApp>true</WindowsStoreApp>
<ApplicationType>Windows Store</ApplicationType>
<UseCrtSDKReference Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReference> <!-- The SDK reference breaks the Hybrid CRT -->
</PropertyGroup>
<PropertyGroup Condition="'$(OpenConsoleUniversalApp)'!='true'">
<!-- Some of our projects include the cppwinrt build options to

View File

@@ -145,4 +145,14 @@
<stage>AlwaysDisabled</stage>
</feature>
<feature>
<name>Feature_ReportErrorsThroughoutAppLifetime</name>
<description>Keep the error handler enabled throughout the lifetime of the application rather than only during startup</description>
<stage>AlwaysEnabled</stage>
<alwaysDisabledBrandingTokens>
<!-- For now, let's just let Release crash. Seeing a bunch of error dialogs might, puzzlingly, make us seem *less* reliable -->
<brandingToken>Release</brandingToken>
</alwaysDisabledBrandingTokens>
</feature>
</featureStaging>

View File

@@ -805,7 +805,7 @@ using Microsoft::Console::VirtualTerminal::StateMachine;
// move cursor to the next line.
pwchBuffer++;
if (gci.IsReturnOnNewlineAutomatic())
if (WI_IsFlagClear(screenInfo.OutputMode, DISABLE_NEWLINE_AUTO_RETURN))
{
// Traditionally, we reset the X position to 0 with a newline automatically.
// Some things might not want this automatic "ONLCR line discipline" (for example, things that are expecting a *NIX behavior.)

View File

@@ -21,6 +21,7 @@ class ModeTests
TEST_METHOD(TestConsoleModeInputScenario);
TEST_METHOD(TestConsoleModeScreenBufferScenario);
TEST_METHOD(TestConsoleModeAcrossMultipleBuffers);
TEST_METHOD(TestGetConsoleDisplayMode);
@@ -94,6 +95,55 @@ void ModeTests::TestConsoleModeScreenBufferScenario()
VERIFY_ARE_EQUAL(dwOutputMode, (DWORD)0, L"Verify able to set zero output flags");
}
void ModeTests::TestConsoleModeAcrossMultipleBuffers()
{
auto dwInitialMode = (DWORD)-1;
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleMode(Common::_hConsole, &dwInitialMode),
L"Get initial output flags");
Log::Comment(L"Verify initial flags match the expected defaults");
VERIFY_IS_TRUE(WI_IsFlagSet(dwInitialMode, ENABLE_PROCESSED_OUTPUT));
VERIFY_IS_TRUE(WI_IsFlagSet(dwInitialMode, ENABLE_WRAP_AT_EOL_OUTPUT));
VERIFY_IS_TRUE(WI_IsFlagClear(dwInitialMode, DISABLE_NEWLINE_AUTO_RETURN));
VERIFY_IS_TRUE(WI_IsFlagClear(dwInitialMode, ENABLE_LVB_GRID_WORLDWIDE));
// The initial VT flag may vary, dependent on the VirtualTerminalLevel registry entry.
const auto defaultVtFlag = WI_IsFlagSet(dwInitialMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
auto dwUpdatedMode = dwInitialMode;
WI_ClearFlag(dwUpdatedMode, ENABLE_PROCESSED_OUTPUT);
WI_ClearFlag(dwUpdatedMode, ENABLE_WRAP_AT_EOL_OUTPUT);
WI_SetFlag(dwUpdatedMode, DISABLE_NEWLINE_AUTO_RETURN);
WI_SetFlag(dwUpdatedMode, ENABLE_LVB_GRID_WORLDWIDE);
WI_UpdateFlag(dwUpdatedMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING, !defaultVtFlag);
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(Common::_hConsole, dwUpdatedMode),
L"Update flags to the opposite of their initial values");
auto hSecondBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
0 /*dwShareMode*/,
nullptr /*lpSecurityAttributes*/,
CONSOLE_TEXTMODE_BUFFER,
nullptr /*lpReserved*/);
VERIFY_ARE_NOT_EQUAL(INVALID_HANDLE_VALUE, hSecondBuffer, L"Create a second screen buffer");
auto dwSecondBufferMode = (DWORD)-1;
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleMode(hSecondBuffer, &dwSecondBufferMode),
L"Get initial flags for second buffer");
VERIFY_ARE_EQUAL(dwInitialMode, dwSecondBufferMode, L"Verify second buffer initialized with defaults");
VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hSecondBuffer, dwSecondBufferMode),
L"Reapply mode to test if it affects the main buffer");
VERIFY_WIN32_BOOL_SUCCEEDED(CloseHandle(hSecondBuffer), L"Close the second buffer");
auto dwFinalMode = (DWORD)-1;
VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleMode(Common::_hConsole, &dwFinalMode),
L"Get flags from the main buffer again");
VERIFY_ARE_EQUAL(dwUpdatedMode, dwFinalMode, L"Verify main buffer flags haven't changed");
}
void ModeTests::TestGetConsoleDisplayMode()
{
DWORD dwMode = 0;

View File

@@ -436,10 +436,6 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
screenInfo.GetStateMachine().ResetState();
}
gci.SetVirtTermLevel(WI_IsFlagSet(dwNewMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING) ? 1 : 0);
gci.SetAutomaticReturnOnNewline(WI_IsFlagSet(screenInfo.OutputMode, DISABLE_NEWLINE_AUTO_RETURN) ? false : true);
gci.SetGridRenderingAllowedWorldwide(WI_IsFlagSet(screenInfo.OutputMode, ENABLE_LVB_GRID_WORLDWIDE));
// if we changed rendering modes then redraw the output buffer,
// but only do this if we're not in conpty mode.
if (!gci.IsInVtIoMode() &&

View File

@@ -166,8 +166,8 @@ void ConhostInternalGetSet::SetScrollingRegion(const til::inclusive_rect& scroll
// - true if a line feed also produces a carriage return. false otherwise.
bool ConhostInternalGetSet::GetLineFeedMode() const
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
return gci.IsReturnOnNewlineAutomatic();
auto& screenInfo = _io.GetActiveOutputBuffer();
return WI_IsFlagClear(screenInfo.OutputMode, DISABLE_NEWLINE_AUTO_RETURN);
}
// Routine Description:

View File

@@ -17,6 +17,13 @@
regular builds, while preventing the build failure during fuzzing builds.
-->
<ConfigurationType Condition="'$(Configuration)'=='Fuzzing'">StaticLibrary</ConfigurationType>
<!--
OpenConsoleProxy gets copied out of our app package and into a shared system store. As such, it can't take a
dependency on any libraries inside our package **or** inside any of our dependency packages. It has to stand
on its own.
-->
<EnableHybridCRT>true</EnableHybridCRT>
</PropertyGroup>
<Import Project="$(SolutionDir)src\common.build.pre.props" />
<ItemGroup>
@@ -77,43 +84,6 @@
</Link>
</ItemDefinitionGroup>
<!--
OpenConsoleProxy gets copied out of our app package and into a shared system store. As such, it can't take a
dependency on any libraries inside our package **or** inside any of our dependency packages. It has to stand
on its own.
Therefore, we're going to use the Hybrid CRT model from WinAppSDK for only OpenConsoleProxy. It statically
links the runtime and STL and dynamically links the UCRT instead of the VC++ CRT. The UCRT ships with Windows.
WinAppSDK asserts that this is "supported according to the CRT maintainer."
-->
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
<Import Project="$(SolutionDir)src\common.build.post.props" />
</Project>

View File

@@ -261,26 +261,20 @@ bool RenderData::IsCursorDoubleWidth() const noexcept
const bool RenderData::IsGridLineDrawingAllowed() noexcept
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
// If virtual terminal output is set, grid line drawing is a must. It is always allowed.
if (WI_IsFlagSet(gci.GetActiveOutputBuffer().OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING))
const auto outputMode = gci.GetActiveOutputBuffer().OutputMode;
// If virtual terminal output is set, grid line drawing is a must. It is also enabled
// if someone explicitly asked for worldwide line drawing.
if (WI_IsAnyFlagSet(outputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_LVB_GRID_WORLDWIDE))
{
return true;
}
else
{
// If someone explicitly asked for worldwide line drawing, enable it.
if (gci.IsGridRenderingAllowedWorldwide())
{
return true;
}
else
{
// Otherwise, for compatibility reasons with legacy applications that used the additional CHAR_INFO bits by accident or for their own purposes,
// we must enable grid line drawing only in a DBCS output codepage. (Line drawing historically only worked in DBCS codepages.)
// The only known instance of this is Image for Windows by TeraByte, Inc. (TeraByte Unlimited) which used the bits accidentally and for no purpose
// (according to the app developer) in conjunction with the Borland Turbo C cgscrn library.
return !!IsAvailableEastAsianCodePage(gci.OutputCP);
}
// Otherwise, for compatibility reasons with legacy applications that used the additional CHAR_INFO bits by accident or for their own purposes,
// we must enable grid line drawing only in a DBCS output codepage. (Line drawing historically only worked in DBCS codepages.)
// The only known instance of this is Image for Windows by TeraByte, Inc. (TeraByte Unlimited) which used the bits accidentally and for no purpose
// (according to the app developer) in conjunction with the Borland Turbo C cgscrn library.
return !!IsAvailableEastAsianCodePage(gci.OutputCP);
}
}

View File

@@ -58,10 +58,11 @@ SCREEN_INFORMATION::SCREEN_INFORMATION(
_desiredFont{ fontInfo },
_ignoreLegacyEquivalentVTAttributes{ false }
{
// Check if VT mode is enabled. Note that this can be true w/o calling
// SetConsoleMode, if VirtualTerminalLevel is set to !=0 in the registry.
// Check if VT mode should be enabled by default. This can be true if
// VirtualTerminalLevel is set to !=0 in the registry, or when conhost
// is started in conpty mode.
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
if (gci.GetVirtTermLevel() != 0)
if (gci.GetDefaultVirtTermLevel() != 0)
{
OutputMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
}
@@ -1913,6 +1914,8 @@ const SCREEN_INFORMATION& SCREEN_INFORMATION::GetMainBuffer() const
auto altCursorPos = myCursor.GetPosition();
altCursorPos.y -= GetVirtualViewport().Top();
altCursor.SetPosition(altCursorPos);
// The alt buffer's output mode should match the main buffer.
createdBuffer->OutputMode = OutputMode;
s_InsertScreenBuffer(createdBuffer);
@@ -2078,6 +2081,9 @@ void SCREEN_INFORMATION::UseMainScreenBuffer()
mainCursor.SetIsVisible(altCursor.IsVisible());
mainCursor.SetBlinkingAllowed(altCursor.IsBlinkingAllowed());
// Copy the alt buffer's output mode back to the main buffer.
psiMain->OutputMode = psiAlt->OutputMode;
s_RemoveScreenBuffer(psiAlt); // this will also delete the alt buffer
// deleting the alt buffer will give the GetSet back to its main

View File

@@ -51,8 +51,6 @@ Settings::Settings() :
_fAllowAltF4Close(true),
_dwVirtTermLevel(0),
_fUseWindowSizePixels(false),
_fAutoReturnOnNewline(true), // the historic Windows behavior defaults this to on.
_fRenderGridWorldwide(false), // historically grid lines were only rendered in DBCS codepages, so this is false by default unless otherwise specified.
// window size pixels initialized below
_fInterceptCopyPaste(0),
_fUseDx(UseDx::Disabled),
@@ -358,11 +356,11 @@ void Settings::Validate()
FAIL_FAST_IF(!(_dwScreenBufferSize.Y > 0));
}
DWORD Settings::GetVirtTermLevel() const
DWORD Settings::GetDefaultVirtTermLevel() const
{
return _dwVirtTermLevel;
}
void Settings::SetVirtTermLevel(const DWORD dwVirtTermLevel)
void Settings::SetDefaultVirtTermLevel(const DWORD dwVirtTermLevel)
{
_dwVirtTermLevel = dwVirtTermLevel;
}
@@ -376,33 +374,6 @@ void Settings::SetAltF4CloseAllowed(const bool fAllowAltF4Close)
_fAllowAltF4Close = fAllowAltF4Close;
}
bool Settings::IsReturnOnNewlineAutomatic() const
{
return _fAutoReturnOnNewline;
}
void Settings::SetAutomaticReturnOnNewline(const bool fAutoReturnOnNewline)
{
_fAutoReturnOnNewline = fAutoReturnOnNewline;
}
bool Settings::IsGridRenderingAllowedWorldwide() const
{
return _fRenderGridWorldwide;
}
void Settings::SetGridRenderingAllowedWorldwide(const bool fGridRenderingAllowed)
{
// Only trigger a notification and update the status if something has changed.
if (_fRenderGridWorldwide != fGridRenderingAllowed)
{
_fRenderGridWorldwide = fGridRenderingAllowed;
if (ServiceLocator::LocateGlobals().pRender != nullptr)
{
ServiceLocator::LocateGlobals().pRender->TriggerRedrawAll();
}
}
}
bool Settings::GetFilterOnPaste() const
{
return _fFilterOnPaste;

View File

@@ -50,18 +50,12 @@ public:
RenderSettings& GetRenderSettings() noexcept { return _renderSettings; };
const RenderSettings& GetRenderSettings() const noexcept { return _renderSettings; };
DWORD GetVirtTermLevel() const;
void SetVirtTermLevel(const DWORD dwVirtTermLevel);
DWORD GetDefaultVirtTermLevel() const;
void SetDefaultVirtTermLevel(const DWORD dwVirtTermLevel);
bool IsAltF4CloseAllowed() const;
void SetAltF4CloseAllowed(const bool fAllowAltF4Close);
bool IsReturnOnNewlineAutomatic() const;
void SetAutomaticReturnOnNewline(const bool fAutoReturnOnNewline);
bool IsGridRenderingAllowedWorldwide() const;
void SetGridRenderingAllowedWorldwide(const bool fGridRenderingAllowed);
bool GetFilterOnPaste() const;
void SetFilterOnPaste(const bool fFilterOnPaste);
@@ -225,8 +219,6 @@ private:
std::wstring _LaunchFaceName;
bool _fAllowAltF4Close;
DWORD _dwVirtTermLevel;
bool _fAutoReturnOnNewline;
bool _fRenderGridWorldwide;
UseDx _fUseDx;
bool _fCopyColor;

View File

@@ -198,7 +198,7 @@ static bool s_IsOnDesktop()
// We want everyone to be using VT by default anyways, so this is a
// strong nudge in that direction. If an application _doesn't_ want VT
// processing, it's free to disable this setting, even in conpty mode.
settings.SetVirtTermLevel(1);
settings.SetDefaultVirtTermLevel(1);
// GH#9458 - In the case of a DefTerm handoff, the OriginalTitle might
// be stashed in the lnk. We want to crack that lnk open, so we can get

View File

@@ -429,7 +429,7 @@ void Telemetry::WriteFinalTraceLog()
TraceLoggingValue(gci.GetScreenBufferSize().width, "ScreenBufferSizeX"),
TraceLoggingValue(gci.GetScreenBufferSize().height, "ScreenBufferSizeY"),
TraceLoggingValue(gci.GetStartupFlags(), "StartupFlags"),
TraceLoggingValue(gci.GetVirtTermLevel(), "VirtualTerminalLevel"),
TraceLoggingValue(gci.GetDefaultVirtTermLevel(), "VirtualTerminalLevel"),
TraceLoggingValue(gci.GetWindowSize().width, "WindowSizeX"),
TraceLoggingValue(gci.GetWindowSize().height, "WindowSizeY"),
TraceLoggingValue(gci.GetWindowOrigin().width, "WindowOriginX"),

View File

@@ -1537,7 +1537,6 @@ void TextBufferTests::TestBackspaceStringsAPI()
const auto& tbi = si.GetTextBuffer();
const auto& cursor = tbi.GetCursor();
gci.SetVirtTermLevel(0);
WI_ClearFlag(si.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
const auto x0 = cursor.GetPosition().x;

View File

@@ -34,12 +34,12 @@ Function Test-MicrosoftPerson($email) {
Function Generate-Thanks($Entry) {
# We don't need to thank ourselves for doing our jobs
If ($_.Microsoft) {
If ($Entry.Microsoft) {
""
} ElseIf (-Not [string]::IsNullOrEmpty($_.PossibleUsername)) {
" (thanks @{0}!)" -f $_.PossibleUsername
} ElseIf (-Not [string]::IsNullOrEmpty($Entry.PossibleUsername)) {
" (thanks @{0}!)" -f $Entry.PossibleUsername
} Else {
" (thanks @<{0}>!)" -f $_.Email
" (thanks @<{0}>!)" -f $Entry.Email
}
}
@@ -54,6 +54,7 @@ Function Get-PossibleUserName($email) {
$Entries = @()
$i = 0
ForEach ($RevisionRange in $RevisionRanges) {
# --pretty=format notes:
# - %an: author name
@@ -70,15 +71,23 @@ ForEach ($RevisionRange in $RevisionRanges) {
Subject = $_.Subject;
Microsoft = (Test-MicrosoftPerson $_.Email);
PossibleUsername = (Get-PossibleUserName $_.Email);
RevRangeID = $i;
} }
$i++
}
$Unique = $Entries | Group-Object Subject | %{ $_.Group[0] | Add-Member Count $_.Count -Force -PassThru }
For($c = 0; $c -Lt $i; $c++) {
" " + ("|" * $c) + "/ " + $RevisionRanges[$c]
}
$Unique = $Entries | Group-Object Subject
$Unique | % {
$c = ""
If ($_.Count -Gt 1) {
$c = "[{0}] " -f $_.Count
$en = $_.Group[0]
$revSpec = (" " * $i)
$_.Group | % {
$revSpec = $revSpec.remove($_.RevRangeID, 1).insert($_.RevRangeID, "X")
}
"* {0}{1}{2}" -f ($c, $_.Subject, (Generate-Thanks $_))
$c = "[{0}] " -f $revSpec
"* {0}{1}{2}" -f ($c, $en.Subject, (Generate-Thanks $en))
}