From addd4ee218267d54166e53367a772da55b368940 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Fri, 5 Dec 2025 16:48:44 -0800 Subject: [PATCH 1/6] cleanup: refactor svccommio class --- src/windows/common/svccommio.cpp | 314 +++++++++++-------------------- src/windows/common/svccommio.hpp | 58 ++++-- 2 files changed, 147 insertions(+), 225 deletions(-) diff --git a/src/windows/common/svccommio.cpp b/src/windows/common/svccommio.cpp index a6a012d1d..d9c0dd718 100644 --- a/src/windows/common/svccommio.cpp +++ b/src/windows/common/svccommio.cpp @@ -18,265 +18,165 @@ Module Name: #pragma hdrstop namespace { -void ChangeConsoleMode(_In_ HANDLE File, _In_ DWORD ConsoleMode) -{ - // - // Use the invalid parameter error code to detect the v1 console that does - // not support the provided mode. This can be improved in the future when - // a more elegant solution exists. - // - // N.B. Ignore failures setting the mode if the console has already - // disconnected. - // - - if (!SetConsoleMode(File, ConsoleMode)) - { - switch (GetLastError()) - { - case ERROR_INVALID_PARAMETER: - THROW_HR(WSL_E_CONSOLE); - - case ERROR_PIPE_NOT_CONNECTED: - break; - default: - THROW_LAST_ERROR(); - } - } +bool IsConsoleHandle(_In_ HANDLE Handle) +{ + DWORD Mode; + return GetFileType(Handle) == FILE_TYPE_CHAR && GetConsoleMode(Handle, &Mode); } -void ConfigureStdHandles(_Inout_ LXSS_STD_HANDLES_INFO& StdHandlesInfo) +void TrySetConsoleMode(_In_ HANDLE Handle, _In_ DWORD Mode) { - // - // Check stdin to see if it is a console or another device. If it is - // a console, configure it to raw processing mode and VT-100 support. If the - // force console I/O is requested, ignore stdin and get active console input - // handle instead. - // - - UINT NewConsoleInputCP = 0; - DWORD NewConsoleInputMode = 0; - BOOLEAN IsConsoleInput = StdHandlesInfo.IsConsoleInput; - BOOLEAN IsConsoleOutput = StdHandlesInfo.IsConsoleOutput; - BOOLEAN IsConsoleError = StdHandlesInfo.IsConsoleError; - DWORD SavedInputMode = StdHandlesInfo.SavedInputMode; - DWORD SavedOutputMode = StdHandlesInfo.SavedOutputMode; - UINT SavedInputCP = StdHandlesInfo.SavedInputCP; - UINT SavedOutputCP = StdHandlesInfo.SavedOutputCP; - CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo; - auto RestoreInputHandle = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] { - if (NewConsoleInputCP != 0) - { - SetConsoleCP(SavedInputCP); - } - - if (NewConsoleInputMode != 0) - { - ChangeConsoleMode(StdHandlesInfo.InputHandle, SavedInputMode); - } - }); - - IsConsoleInput = FALSE; - if ((GetFileType(StdHandlesInfo.InputHandle) == FILE_TYPE_CHAR) && (GetConsoleMode(StdHandlesInfo.InputHandle, &SavedInputMode))) + if (!SetConsoleMode(Handle, Mode)) { - IsConsoleInput = TRUE; - NewConsoleInputMode = SavedInputMode; - WI_SetAllFlags(NewConsoleInputMode, (ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT)); - WI_ClearAllFlags(NewConsoleInputMode, (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT)); - ChangeConsoleMode(StdHandlesInfo.InputHandle, NewConsoleInputMode); - - // - // Set the console input to the UTF-8 code page. - // - - SavedInputCP = GetConsoleCP(); - NewConsoleInputCP = CP_UTF8; - THROW_LAST_ERROR_IF(!::SetConsoleCP(NewConsoleInputCP)); - } - - bool RestoreMode = false; - bool RestoreCp = false; - auto RestoreOutput = wil::scope_exit([&] { - if (RestoreMode) + const auto Error = GetLastError(); + if (Error != ERROR_INVALID_PARAMETER && Error != ERROR_PIPE_NOT_CONNECTED) { - SetConsoleMode(StdHandlesInfo.ConsoleOutputHandle.get(), SavedOutputMode); + LOG_IF_WIN32_ERROR(Error); } + } +} - if (RestoreCp) - { - SetConsoleOutputCP(SavedOutputCP); - } - }); +} // namespace - // - // If there is a console output handle, save the output mode and codepage so - // it can be restored. - // +namespace wsl::windows::common { - if (StdHandlesInfo.ConsoleOutputHandle) +// ConsoleInput implementation +std::unique_ptr ConsoleInput::Create(HANDLE Handle) +{ + DWORD Mode; + if (GetFileType(Handle) == FILE_TYPE_CHAR && GetConsoleMode(Handle, &Mode)) { - THROW_LAST_ERROR_IF(!::GetConsoleMode(StdHandlesInfo.ConsoleOutputHandle.get(), &SavedOutputMode)); - - // - // Temporarily try both with and without the custom flag to disable newline - // auto return. - // - - DWORD NewConsoleOutputMode = SavedOutputMode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN; - if (SetConsoleMode(StdHandlesInfo.ConsoleOutputHandle.get(), NewConsoleOutputMode) == FALSE) - { - WI_ClearFlag(NewConsoleOutputMode, DISABLE_NEWLINE_AUTO_RETURN); - ChangeConsoleMode(StdHandlesInfo.ConsoleOutputHandle.get(), NewConsoleOutputMode); - } - - RestoreMode = true; - - // - // Set the console output to the UTF-8 code page. - // + return std::unique_ptr(new ConsoleInput(Handle, Mode)); + } - SavedOutputCP = GetConsoleOutputCP(); - THROW_LAST_ERROR_IF(!::SetConsoleOutputCP(CP_UTF8)); + return nullptr; +} - RestoreCp = true; - } +ConsoleInput::ConsoleInput(HANDLE Handle, DWORD SavedMode) : m_Handle(Handle), m_SavedMode(SavedMode) +{ + // Save code page + m_SavedCodePage = GetConsoleCP(); - // - // If the force console I/O is requested, ignore stdout and treat the - // console as the output handle. - // + // Configure for raw input with VT support + DWORD NewMode = m_SavedMode; + WI_SetAllFlags(NewMode, ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT); + WI_ClearAllFlags(NewMode, ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); + TrySetConsoleMode(Handle, NewMode); - IsConsoleOutput = FALSE; - if ((GetFileType(StdHandlesInfo.OutputHandle) == FILE_TYPE_CHAR) && - (GetConsoleScreenBufferInfo(StdHandlesInfo.OutputHandle, &ScreenBufferInfo))) - { - IsConsoleOutput = TRUE; - } + // Set UTF-8 code page + SetConsoleCP(CP_UTF8); +} - IsConsoleError = FALSE; - if ((GetFileType(StdHandlesInfo.ErrorHandle) == FILE_TYPE_CHAR) && - (GetConsoleScreenBufferInfo(StdHandlesInfo.ErrorHandle, &ScreenBufferInfo))) +ConsoleInput::~ConsoleInput() +{ + if (m_Handle) { - IsConsoleError = TRUE; + TrySetConsoleMode(m_Handle, m_SavedMode); + SetConsoleCP(m_SavedCodePage); } - - RestoreInputHandle.release(); - RestoreOutput.release(); - StdHandlesInfo.IsConsoleInput = IsConsoleInput; - StdHandlesInfo.IsConsoleOutput = IsConsoleOutput; - StdHandlesInfo.IsConsoleError = IsConsoleError; - StdHandlesInfo.SavedInputMode = SavedInputMode; - StdHandlesInfo.SavedOutputMode = SavedOutputMode; - StdHandlesInfo.SavedInputCP = SavedInputCP; - StdHandlesInfo.SavedOutputCP = SavedOutputCP; } -} // namespace -wsl::windows::common::SvcCommIo::SvcCommIo() +// ConsoleOutput implementation +std::unique_ptr ConsoleOutput::Create() { - _stdHandlesInfo.InputHandle = GetStdHandle(STD_INPUT_HANDLE); - _stdHandlesInfo.OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE); - _stdHandlesInfo.ErrorHandle = GetStdHandle(STD_ERROR_HANDLE); - _stdHandlesInfo.ConsoleOutputHandle.reset( + wil::unique_hfile ConsoleHandle( CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr)); - ConfigureStdHandles(_stdHandlesInfo); - _stdHandles.StdIn.HandleType = LxssHandleInput; - _stdHandles.StdIn.Handle = HandleToUlong(_stdHandlesInfo.InputHandle); - _stdHandles.StdOut.HandleType = LxssHandleOutput; - _stdHandles.StdOut.Handle = HandleToUlong(_stdHandlesInfo.OutputHandle); - _stdHandles.StdErr.HandleType = LxssHandleOutput; - _stdHandles.StdErr.Handle = HandleToUlong(_stdHandlesInfo.ErrorHandle); - - // - // N.B.: The console handle is not supposed to be closed, it is just copied - // from PEB. - // - - if (_stdHandlesInfo.IsConsoleInput) + if (!ConsoleHandle) { - _stdHandles.StdIn.Handle = LXSS_HANDLE_USE_CONSOLE; - _stdHandles.StdIn.HandleType = LxssHandleConsole; + return nullptr; } - if (_stdHandlesInfo.IsConsoleOutput) + DWORD Mode; + if (GetConsoleMode(ConsoleHandle.get(), &Mode)) { - _stdHandles.StdOut.Handle = LXSS_HANDLE_USE_CONSOLE; - _stdHandles.StdOut.HandleType = LxssHandleConsole; + return std::unique_ptr(new ConsoleOutput(std::move(ConsoleHandle), Mode)); } - if (_stdHandlesInfo.IsConsoleError) - { - _stdHandles.StdErr.Handle = LXSS_HANDLE_USE_CONSOLE; - _stdHandles.StdErr.HandleType = LxssHandleConsole; - } + return nullptr; } -wsl::windows::common::SvcCommIo::~SvcCommIo() +ConsoleOutput::ConsoleOutput(wil::unique_hfile ConsoleHandle, DWORD SavedMode) : + m_ConsoleHandle(std::move(ConsoleHandle)), m_SavedMode(SavedMode) { - try + // Save code page + m_SavedCodePage = GetConsoleOutputCP(); + + // Configure for VT output with DISABLE_NEWLINE_AUTO_RETURN + DWORD NewMode = m_SavedMode; + WI_SetAllFlags(NewMode, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN); + + // Try with DISABLE_NEWLINE_AUTO_RETURN first, fall back without it if not supported + if (!SetConsoleMode(m_ConsoleHandle.get(), NewMode)) { - RestoreConsoleMode(); + WI_ClearFlag(NewMode, DISABLE_NEWLINE_AUTO_RETURN); + TrySetConsoleMode(m_ConsoleHandle.get(), NewMode); } - CATCH_LOG() -} -PLXSS_STD_HANDLES -wsl::windows::common::SvcCommIo::GetStdHandles() -{ - return &_stdHandles; + // Set UTF-8 code page + SetConsoleOutputCP(CP_UTF8); } -COORD -wsl::windows::common::SvcCommIo::GetWindowSize() const +ConsoleOutput::~ConsoleOutput() { - CONSOLE_SCREEN_BUFFER_INFOEX Info{}; - Info.cbSize = sizeof(Info); - if (_stdHandlesInfo.IsConsoleOutput) + if (m_ConsoleHandle) { - THROW_IF_WIN32_BOOL_FALSE(::GetConsoleScreenBufferInfoEx(_stdHandlesInfo.OutputHandle, &Info)); + TrySetConsoleMode(m_ConsoleHandle.get(), m_SavedMode); + SetConsoleOutputCP(m_SavedCodePage); } - else if (_stdHandlesInfo.IsConsoleError) - { - THROW_IF_WIN32_BOOL_FALSE(::GetConsoleScreenBufferInfoEx(_stdHandlesInfo.ErrorHandle, &Info)); - } - - return { - static_cast(Info.srWindow.Right - Info.srWindow.Left + 1), static_cast(Info.srWindow.Bottom - Info.srWindow.Top + 1)}; } -void wsl::windows::common::SvcCommIo::RestoreConsoleMode() const - -/*++ - -Routine Description: +// SvcCommIo implementation +SvcCommIo::SvcCommIo() +{ + const HANDLE InputHandle = GetStdHandle(STD_INPUT_HANDLE); + const HANDLE OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE); + const HANDLE ErrorHandle = GetStdHandle(STD_ERROR_HANDLE); - Restores the saved input/output console mode. + // Configure input console + m_ConsoleInput = ConsoleInput::Create(InputHandle); -Arguments: + // Configure output console + m_ConsoleOutput = ConsoleOutput::Create(); - None. + // Initialize the standard handles structure + const bool IsConsoleInput = m_ConsoleInput != nullptr; + m_StdHandles.StdIn.HandleType = IsConsoleInput ? LxssHandleConsole : LxssHandleInput; + m_StdHandles.StdIn.Handle = IsConsoleInput ? LXSS_HANDLE_USE_CONSOLE : HandleToUlong(InputHandle); -Return Value: + const bool IsConsoleOutput = IsConsoleHandle(OutputHandle); + m_StdHandles.StdOut.HandleType = IsConsoleOutput ? LxssHandleConsole : LxssHandleOutput; + m_StdHandles.StdOut.Handle = IsConsoleOutput ? LXSS_HANDLE_USE_CONSOLE : HandleToUlong(OutputHandle); - None. + const bool IsConsoleError = IsConsoleHandle(ErrorHandle); + m_StdHandles.StdErr.HandleType = IsConsoleError ? LxssHandleConsole : LxssHandleOutput; + m_StdHandles.StdErr.Handle = IsConsoleError ? LXSS_HANDLE_USE_CONSOLE : HandleToUlong(ErrorHandle); ---*/ + // Cache a console handle for GetWindowSize + m_WindowSizeHandle = IsConsoleOutput ? OutputHandle : (IsConsoleError ? ErrorHandle : nullptr); +} +PLXSS_STD_HANDLES +SvcCommIo::GetStdHandles() { - // - // Restore the console input and output modes. - // + return &m_StdHandles; +} - if (_stdHandlesInfo.ConsoleOutputHandle) +COORD +SvcCommIo::GetWindowSize() const +{ + if (m_WindowSizeHandle) { - ChangeConsoleMode(_stdHandlesInfo.ConsoleOutputHandle.get(), _stdHandlesInfo.SavedOutputMode); - SetConsoleOutputCP(_stdHandlesInfo.SavedOutputCP); + CONSOLE_SCREEN_BUFFER_INFOEX Info{}; + Info.cbSize = sizeof(Info); + THROW_IF_WIN32_BOOL_FALSE(GetConsoleScreenBufferInfoEx(m_WindowSizeHandle, &Info)); + return { + static_cast(Info.srWindow.Right - Info.srWindow.Left + 1), + static_cast(Info.srWindow.Bottom - Info.srWindow.Top + 1)}; } - if (_stdHandlesInfo.IsConsoleInput != FALSE) - { - ChangeConsoleMode(_stdHandlesInfo.InputHandle, _stdHandlesInfo.SavedInputMode); - SetConsoleCP(_stdHandlesInfo.SavedInputCP); - } + return {80, 24}; // Default size if no console } + +} // namespace wsl::windows::common diff --git a/src/windows/common/svccommio.hpp b/src/windows/common/svccommio.hpp index 95de9b263..a734781a0 100644 --- a/src/windows/common/svccommio.hpp +++ b/src/windows/common/svccommio.hpp @@ -18,35 +18,57 @@ Module Name: #include #include "wslservice.h" -typedef struct _LXSS_STD_HANDLES_INFO +namespace wsl::windows::common { + +// RAII wrapper for console input configuration and restoration +class ConsoleInput { - HANDLE InputHandle; - HANDLE OutputHandle; - HANDLE ErrorHandle; - wil::unique_hfile ConsoleOutputHandle; - BOOLEAN IsConsoleInput; - BOOLEAN IsConsoleOutput; - BOOLEAN IsConsoleError; - DWORD SavedInputMode; - DWORD SavedOutputMode; - UINT SavedInputCP; - UINT SavedOutputCP; -} LXSS_STD_HANDLES_INFO, *PLXSS_STD_HANDLES_INFO; +public: + static std::unique_ptr Create(HANDLE Handle); + ~ConsoleInput(); + ConsoleInput(const ConsoleInput&) = delete; + ConsoleInput& operator=(const ConsoleInput&) = delete; + +private: + ConsoleInput(HANDLE Handle, DWORD SavedMode); + + HANDLE m_Handle = nullptr; + DWORD m_SavedMode = 0; + UINT m_SavedCodePage = 0; +}; + +// RAII wrapper for console output configuration and restoration +class ConsoleOutput +{ +public: + static std::unique_ptr Create(); + ~ConsoleOutput(); + ConsoleOutput(const ConsoleOutput&) = delete; + ConsoleOutput& operator=(const ConsoleOutput&) = delete; + +private: + ConsoleOutput(wil::unique_hfile ConsoleHandle, DWORD SavedMode); + + wil::unique_hfile m_ConsoleHandle; + DWORD m_SavedMode = 0; + UINT m_SavedCodePage = 0; +}; -namespace wsl::windows::common { class SvcCommIo { public: SvcCommIo(); - ~SvcCommIo(); + ~SvcCommIo() = default; PLXSS_STD_HANDLES GetStdHandles(); COORD GetWindowSize() const; private: - void RestoreConsoleMode() const; + LXSS_STD_HANDLES m_StdHandles{}; + HANDLE m_WindowSizeHandle = nullptr; // Cached console handle for GetWindowSize - LXSS_STD_HANDLES _stdHandles{}; - LXSS_STD_HANDLES_INFO _stdHandlesInfo{}; + // RAII members for automatic restoration + std::unique_ptr m_ConsoleInput; + std::unique_ptr m_ConsoleOutput; }; } // namespace wsl::windows::common From c77fded5a874bcce57993d51d85c193c890037b6 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Fri, 5 Dec 2025 17:12:33 -0800 Subject: [PATCH 2/6] add logging if setting code page fails --- src/windows/common/svccommio.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/windows/common/svccommio.cpp b/src/windows/common/svccommio.cpp index d9c0dd718..f664b5096 100644 --- a/src/windows/common/svccommio.cpp +++ b/src/windows/common/svccommio.cpp @@ -65,7 +65,7 @@ ConsoleInput::ConsoleInput(HANDLE Handle, DWORD SavedMode) : m_Handle(Handle), m TrySetConsoleMode(Handle, NewMode); // Set UTF-8 code page - SetConsoleCP(CP_UTF8); + LOG_IF_WIN32_BOOL_FALSE(SetConsoleCP(CP_UTF8)); } ConsoleInput::~ConsoleInput() @@ -73,7 +73,7 @@ ConsoleInput::~ConsoleInput() if (m_Handle) { TrySetConsoleMode(m_Handle, m_SavedMode); - SetConsoleCP(m_SavedCodePage); + LOG_IF_WIN32_BOOL_FALSE(SetConsoleCP(m_SavedCodePage)); } } @@ -115,7 +115,7 @@ ConsoleOutput::ConsoleOutput(wil::unique_hfile ConsoleHandle, DWORD SavedMode) : } // Set UTF-8 code page - SetConsoleOutputCP(CP_UTF8); + LOG_IF_WIN32_BOOL_FALSE(SetConsoleOutputCP(CP_UTF8)); } ConsoleOutput::~ConsoleOutput() @@ -123,7 +123,7 @@ ConsoleOutput::~ConsoleOutput() if (m_ConsoleHandle) { TrySetConsoleMode(m_ConsoleHandle.get(), m_SavedMode); - SetConsoleOutputCP(m_SavedCodePage); + LOG_IF_WIN32_BOOL_FALSE(SetConsoleOutputCP(m_SavedCodePage)); } } From fb985df18ae3c0fd40cbbbdad95507bf5c79f9ac Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Wed, 17 Dec 2025 08:43:32 -0800 Subject: [PATCH 3/6] pr feedback --- src/windows/common/svccommio.cpp | 90 +++++++++++++++++++------------- src/windows/common/svccommio.hpp | 13 +++-- 2 files changed, 64 insertions(+), 39 deletions(-) diff --git a/src/windows/common/svccommio.cpp b/src/windows/common/svccommio.cpp index f664b5096..6d711e036 100644 --- a/src/windows/common/svccommio.cpp +++ b/src/windows/common/svccommio.cpp @@ -25,46 +25,76 @@ bool IsConsoleHandle(_In_ HANDLE Handle) return GetFileType(Handle) == FILE_TYPE_CHAR && GetConsoleMode(Handle, &Mode); } -void TrySetConsoleMode(_In_ HANDLE Handle, _In_ DWORD Mode) +void ChangeConsoleMode(_In_ HANDLE Handle, _In_ DWORD Mode) { + // + // Use the invalid parameter error code to detect the v1 console that does + // not support the provided mode. This can be improved in the future when + // a more elegant solution exists. + // + // N.B. Ignore failures setting the mode if the console has already + // disconnected. + // + if (!SetConsoleMode(Handle, Mode)) { - const auto Error = GetLastError(); - if (Error != ERROR_INVALID_PARAMETER && Error != ERROR_PIPE_NOT_CONNECTED) + // DISABLE_NEWLINE_AUTO_RETURN is not supported everywhere, if the flag was present fall back and try again. + if (WI_IsFlagSet(Mode, DISABLE_NEWLINE_AUTO_RETURN)) + { + if (SetConsoleMode(Handle, WI_ClearFlag(Mode, DISABLE_NEWLINE_AUTO_RETURN))) + { + return; + } + } + + switch (GetLastError()) { - LOG_IF_WIN32_ERROR(Error); + case ERROR_INVALID_PARAMETER: + THROW_HR(WSL_E_CONSOLE); + + case ERROR_PIPE_NOT_CONNECTED: + break; + + default: + THROW_LAST_ERROR(); } } } +void TrySetConsoleMode(_In_ HANDLE Handle, _In_ DWORD Mode) +try +{ + ChangeConsoleMode(Handle, Mode); +} +CATCH_LOG() + } // namespace namespace wsl::windows::common { -// ConsoleInput implementation -std::unique_ptr ConsoleInput::Create(HANDLE Handle) +std::optional ConsoleInput::Create(HANDLE Handle) { DWORD Mode; if (GetFileType(Handle) == FILE_TYPE_CHAR && GetConsoleMode(Handle, &Mode)) { - return std::unique_ptr(new ConsoleInput(Handle, Mode)); + return ConsoleInput(Handle, Mode); } - return nullptr; + return std::nullopt; } ConsoleInput::ConsoleInput(HANDLE Handle, DWORD SavedMode) : m_Handle(Handle), m_SavedMode(SavedMode) { - // Save code page + // Save code page. m_SavedCodePage = GetConsoleCP(); - // Configure for raw input with VT support + // Configure for raw input with VT support. DWORD NewMode = m_SavedMode; WI_SetAllFlags(NewMode, ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT); WI_ClearAllFlags(NewMode, ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); - TrySetConsoleMode(Handle, NewMode); + ChangeConsoleMode(Handle, NewMode); - // Set UTF-8 code page + // Set UTF-8 code page. LOG_IF_WIN32_BOOL_FALSE(SetConsoleCP(CP_UTF8)); } @@ -77,44 +107,35 @@ ConsoleInput::~ConsoleInput() } } -// ConsoleOutput implementation -std::unique_ptr ConsoleOutput::Create() +std::optional ConsoleOutput::Create() { wil::unique_hfile ConsoleHandle( CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr)); - if (!ConsoleHandle) - { - return nullptr; - } - - DWORD Mode; - if (GetConsoleMode(ConsoleHandle.get(), &Mode)) + if (ConsoleHandle) { - return std::unique_ptr(new ConsoleOutput(std::move(ConsoleHandle), Mode)); + DWORD Mode; + if (GetConsoleMode(ConsoleHandle.get(), &Mode)) + { + return ConsoleOutput(std::move(ConsoleHandle), Mode); + } } - return nullptr; + return std::nullopt; } ConsoleOutput::ConsoleOutput(wil::unique_hfile ConsoleHandle, DWORD SavedMode) : m_ConsoleHandle(std::move(ConsoleHandle)), m_SavedMode(SavedMode) { - // Save code page + // Save code page. m_SavedCodePage = GetConsoleOutputCP(); - // Configure for VT output with DISABLE_NEWLINE_AUTO_RETURN + // Configure for VT output. DWORD NewMode = m_SavedMode; WI_SetAllFlags(NewMode, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN); + ChangeConsoleMode(m_ConsoleHandle.get(), NewMode); - // Try with DISABLE_NEWLINE_AUTO_RETURN first, fall back without it if not supported - if (!SetConsoleMode(m_ConsoleHandle.get(), NewMode)) - { - WI_ClearFlag(NewMode, DISABLE_NEWLINE_AUTO_RETURN); - TrySetConsoleMode(m_ConsoleHandle.get(), NewMode); - } - - // Set UTF-8 code page + // Set UTF-8 code page. LOG_IF_WIN32_BOOL_FALSE(SetConsoleOutputCP(CP_UTF8)); } @@ -127,7 +148,6 @@ ConsoleOutput::~ConsoleOutput() } } -// SvcCommIo implementation SvcCommIo::SvcCommIo() { const HANDLE InputHandle = GetStdHandle(STD_INPUT_HANDLE); @@ -141,7 +161,7 @@ SvcCommIo::SvcCommIo() m_ConsoleOutput = ConsoleOutput::Create(); // Initialize the standard handles structure - const bool IsConsoleInput = m_ConsoleInput != nullptr; + const bool IsConsoleInput = m_ConsoleInput.has_value(); m_StdHandles.StdIn.HandleType = IsConsoleInput ? LxssHandleConsole : LxssHandleInput; m_StdHandles.StdIn.Handle = IsConsoleInput ? LXSS_HANDLE_USE_CONSOLE : HandleToUlong(InputHandle); diff --git a/src/windows/common/svccommio.hpp b/src/windows/common/svccommio.hpp index a734781a0..35087ee9a 100644 --- a/src/windows/common/svccommio.hpp +++ b/src/windows/common/svccommio.hpp @@ -14,6 +14,7 @@ Module Name: #pragma once +#include #include #include #include "wslservice.h" @@ -24,10 +25,12 @@ namespace wsl::windows::common { class ConsoleInput { public: - static std::unique_ptr Create(HANDLE Handle); + static std::optional Create(HANDLE Handle); ~ConsoleInput(); ConsoleInput(const ConsoleInput&) = delete; ConsoleInput& operator=(const ConsoleInput&) = delete; + ConsoleInput(ConsoleInput&&) = default; + ConsoleInput& operator=(ConsoleInput&&) = default; private: ConsoleInput(HANDLE Handle, DWORD SavedMode); @@ -41,10 +44,12 @@ class ConsoleInput class ConsoleOutput { public: - static std::unique_ptr Create(); + static std::optional Create(); ~ConsoleOutput(); ConsoleOutput(const ConsoleOutput&) = delete; ConsoleOutput& operator=(const ConsoleOutput&) = delete; + ConsoleOutput(ConsoleOutput&&) = default; + ConsoleOutput& operator=(ConsoleOutput&&) = default; private: ConsoleOutput(wil::unique_hfile ConsoleHandle, DWORD SavedMode); @@ -68,7 +73,7 @@ class SvcCommIo HANDLE m_WindowSizeHandle = nullptr; // Cached console handle for GetWindowSize // RAII members for automatic restoration - std::unique_ptr m_ConsoleInput; - std::unique_ptr m_ConsoleOutput; + std::optional m_ConsoleInput; + std::optional m_ConsoleOutput; }; } // namespace wsl::windows::common From 2fd46f5de8e71d7674f16683b0e5b91b4d3f2cf2 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Fri, 19 Dec 2025 09:42:41 -0800 Subject: [PATCH 4/6] remove unneeded if --- src/windows/common/svccommio.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/windows/common/svccommio.cpp b/src/windows/common/svccommio.cpp index 6d711e036..cf9e33be3 100644 --- a/src/windows/common/svccommio.cpp +++ b/src/windows/common/svccommio.cpp @@ -100,11 +100,8 @@ ConsoleInput::ConsoleInput(HANDLE Handle, DWORD SavedMode) : m_Handle(Handle), m ConsoleInput::~ConsoleInput() { - if (m_Handle) - { - TrySetConsoleMode(m_Handle, m_SavedMode); - LOG_IF_WIN32_BOOL_FALSE(SetConsoleCP(m_SavedCodePage)); - } + TrySetConsoleMode(m_Handle, m_SavedMode); + LOG_IF_WIN32_BOOL_FALSE(SetConsoleCP(m_SavedCodePage)); } std::optional ConsoleOutput::Create() From b367e20679e3015a2f1d720bc4ce8edef6b43ee3 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Fri, 19 Dec 2025 14:14:22 -0800 Subject: [PATCH 5/6] remove unneeded if --- src/windows/common/svccommio.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/windows/common/svccommio.cpp b/src/windows/common/svccommio.cpp index cf9e33be3..81cd2bef1 100644 --- a/src/windows/common/svccommio.cpp +++ b/src/windows/common/svccommio.cpp @@ -138,11 +138,8 @@ ConsoleOutput::ConsoleOutput(wil::unique_hfile ConsoleHandle, DWORD SavedMode) : ConsoleOutput::~ConsoleOutput() { - if (m_ConsoleHandle) - { - TrySetConsoleMode(m_ConsoleHandle.get(), m_SavedMode); - LOG_IF_WIN32_BOOL_FALSE(SetConsoleOutputCP(m_SavedCodePage)); - } + TrySetConsoleMode(m_ConsoleHandle.get(), m_SavedMode); + LOG_IF_WIN32_BOOL_FALSE(SetConsoleOutputCP(m_SavedCodePage)); } SvcCommIo::SvcCommIo() From c8ff07980c20b0e0806e15b314a1128acd0fdb29 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Tue, 6 Jan 2026 12:29:06 -0800 Subject: [PATCH 6/6] pr feedbacK' --- src/windows/common/svccommio.cpp | 5 +++-- src/windows/common/svccommio.hpp | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/windows/common/svccommio.cpp b/src/windows/common/svccommio.cpp index 81cd2bef1..33c966f5e 100644 --- a/src/windows/common/svccommio.cpp +++ b/src/windows/common/svccommio.cpp @@ -121,7 +121,7 @@ std::optional ConsoleOutput::Create() return std::nullopt; } -ConsoleOutput::ConsoleOutput(wil::unique_hfile ConsoleHandle, DWORD SavedMode) : +ConsoleOutput::ConsoleOutput(wil::unique_hfile&& ConsoleHandle, DWORD SavedMode) : m_ConsoleHandle(std::move(ConsoleHandle)), m_SavedMode(SavedMode) { // Save code page. @@ -190,7 +190,8 @@ SvcCommIo::GetWindowSize() const static_cast(Info.srWindow.Bottom - Info.srWindow.Top + 1)}; } - return {80, 24}; // Default size if no console + LOG_HR_MSG(E_UNEXPECTED, "No console handle available for GetWindowSize"); + return {80, 24}; } } // namespace wsl::windows::common diff --git a/src/windows/common/svccommio.hpp b/src/windows/common/svccommio.hpp index 35087ee9a..64533dbcc 100644 --- a/src/windows/common/svccommio.hpp +++ b/src/windows/common/svccommio.hpp @@ -52,7 +52,7 @@ class ConsoleOutput ConsoleOutput& operator=(ConsoleOutput&&) = default; private: - ConsoleOutput(wil::unique_hfile ConsoleHandle, DWORD SavedMode); + ConsoleOutput(wil::unique_hfile&& ConsoleHandle, DWORD SavedMode); wil::unique_hfile m_ConsoleHandle; DWORD m_SavedMode = 0; @@ -63,7 +63,6 @@ class SvcCommIo { public: SvcCommIo(); - ~SvcCommIo() = default; PLXSS_STD_HANDLES GetStdHandles(); COORD GetWindowSize() const;