@@ -18,265 +18,165 @@ Module Name:
1818#pragma hdrstop
1919
2020namespace {
21- void ChangeConsoleMode (_In_ HANDLE File, _In_ DWORD ConsoleMode)
22- {
23- //
24- // Use the invalid parameter error code to detect the v1 console that does
25- // not support the provided mode. This can be improved in the future when
26- // a more elegant solution exists.
27- //
28- // N.B. Ignore failures setting the mode if the console has already
29- // disconnected.
30- //
31-
32- if (!SetConsoleMode (File, ConsoleMode))
33- {
34- switch (GetLastError ())
35- {
36- case ERROR_INVALID_PARAMETER:
37- THROW_HR (WSL_E_CONSOLE);
38-
39- case ERROR_PIPE_NOT_CONNECTED:
40- break ;
4121
42- default :
43- THROW_LAST_ERROR ();
44- }
45- }
22+ bool IsConsoleHandle (_In_ HANDLE Handle)
23+ {
24+ DWORD Mode;
25+ return GetFileType (Handle) == FILE_TYPE_CHAR && GetConsoleMode (Handle, &Mode);
4626}
4727
48- void ConfigureStdHandles (_Inout_ LXSS_STD_HANDLES_INFO& StdHandlesInfo )
28+ void TrySetConsoleMode (_In_ HANDLE Handle, _In_ DWORD Mode )
4929{
50- //
51- // Check stdin to see if it is a console or another device. If it is
52- // a console, configure it to raw processing mode and VT-100 support. If the
53- // force console I/O is requested, ignore stdin and get active console input
54- // handle instead.
55- //
56-
57- UINT NewConsoleInputCP = 0 ;
58- DWORD NewConsoleInputMode = 0 ;
59- BOOLEAN IsConsoleInput = StdHandlesInfo.IsConsoleInput ;
60- BOOLEAN IsConsoleOutput = StdHandlesInfo.IsConsoleOutput ;
61- BOOLEAN IsConsoleError = StdHandlesInfo.IsConsoleError ;
62- DWORD SavedInputMode = StdHandlesInfo.SavedInputMode ;
63- DWORD SavedOutputMode = StdHandlesInfo.SavedOutputMode ;
64- UINT SavedInputCP = StdHandlesInfo.SavedInputCP ;
65- UINT SavedOutputCP = StdHandlesInfo.SavedOutputCP ;
66- CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
67- auto RestoreInputHandle = wil::scope_exit_log (WI_DIAGNOSTICS_INFO, [&] {
68- if (NewConsoleInputCP != 0 )
69- {
70- SetConsoleCP (SavedInputCP);
71- }
72-
73- if (NewConsoleInputMode != 0 )
74- {
75- ChangeConsoleMode (StdHandlesInfo.InputHandle , SavedInputMode);
76- }
77- });
78-
79- IsConsoleInput = FALSE ;
80- if ((GetFileType (StdHandlesInfo.InputHandle ) == FILE_TYPE_CHAR) && (GetConsoleMode (StdHandlesInfo.InputHandle , &SavedInputMode)))
30+ if (!SetConsoleMode (Handle, Mode))
8131 {
82- IsConsoleInput = TRUE ;
83- NewConsoleInputMode = SavedInputMode;
84- WI_SetAllFlags (NewConsoleInputMode, (ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT));
85- WI_ClearAllFlags (NewConsoleInputMode, (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT));
86- ChangeConsoleMode (StdHandlesInfo.InputHandle , NewConsoleInputMode);
87-
88- //
89- // Set the console input to the UTF-8 code page.
90- //
91-
92- SavedInputCP = GetConsoleCP ();
93- NewConsoleInputCP = CP_UTF8;
94- THROW_LAST_ERROR_IF (!::SetConsoleCP (NewConsoleInputCP));
95- }
96-
97- bool RestoreMode = false ;
98- bool RestoreCp = false ;
99- auto RestoreOutput = wil::scope_exit ([&] {
100- if (RestoreMode)
32+ const auto Error = GetLastError ();
33+ if (Error != ERROR_INVALID_PARAMETER && Error != ERROR_PIPE_NOT_CONNECTED)
10134 {
102- SetConsoleMode (StdHandlesInfo. ConsoleOutputHandle . get (), SavedOutputMode );
35+ LOG_IF_WIN32_ERROR (Error );
10336 }
37+ }
38+ }
10439
105- if (RestoreCp)
106- {
107- SetConsoleOutputCP (SavedOutputCP);
108- }
109- });
40+ } // namespace
11041
111- //
112- // If there is a console output handle, save the output mode and codepage so
113- // it can be restored.
114- //
42+ namespace wsl ::windows::common {
11543
116- if (StdHandlesInfo.ConsoleOutputHandle )
44+ // ConsoleInput implementation
45+ std::unique_ptr<ConsoleInput> ConsoleInput::Create (HANDLE Handle)
46+ {
47+ DWORD Mode;
48+ if (GetFileType (Handle) == FILE_TYPE_CHAR && GetConsoleMode (Handle, &Mode))
11749 {
118- THROW_LAST_ERROR_IF (!::GetConsoleMode (StdHandlesInfo.ConsoleOutputHandle .get (), &SavedOutputMode));
119-
120- //
121- // Temporarily try both with and without the custom flag to disable newline
122- // auto return.
123- //
124-
125- DWORD NewConsoleOutputMode = SavedOutputMode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
126- if (SetConsoleMode (StdHandlesInfo.ConsoleOutputHandle .get (), NewConsoleOutputMode) == FALSE )
127- {
128- WI_ClearFlag (NewConsoleOutputMode, DISABLE_NEWLINE_AUTO_RETURN);
129- ChangeConsoleMode (StdHandlesInfo.ConsoleOutputHandle .get (), NewConsoleOutputMode);
130- }
131-
132- RestoreMode = true ;
133-
134- //
135- // Set the console output to the UTF-8 code page.
136- //
50+ return std::unique_ptr<ConsoleInput>(new ConsoleInput (Handle, Mode));
51+ }
13752
138- SavedOutputCP = GetConsoleOutputCP () ;
139- THROW_LAST_ERROR_IF (!:: SetConsoleOutputCP (CP_UTF8));
53+ return nullptr ;
54+ }
14055
141- RestoreCp = true ;
142- }
56+ ConsoleInput::ConsoleInput (HANDLE Handle, DWORD SavedMode) : m_Handle(Handle), m_SavedMode(SavedMode)
57+ {
58+ // Save code page
59+ m_SavedCodePage = GetConsoleCP ();
14360
144- //
145- // If the force console I/O is requested, ignore stdout and treat the
146- // console as the output handle.
147- //
61+ // Configure for raw input with VT support
62+ DWORD NewMode = m_SavedMode;
63+ WI_SetAllFlags (NewMode, ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT);
64+ WI_ClearAllFlags (NewMode, ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
65+ TrySetConsoleMode (Handle, NewMode);
14866
149- IsConsoleOutput = FALSE ;
150- if ((GetFileType (StdHandlesInfo.OutputHandle ) == FILE_TYPE_CHAR) &&
151- (GetConsoleScreenBufferInfo (StdHandlesInfo.OutputHandle , &ScreenBufferInfo)))
152- {
153- IsConsoleOutput = TRUE ;
154- }
67+ // Set UTF-8 code page
68+ SetConsoleCP (CP_UTF8);
69+ }
15570
156- IsConsoleError = FALSE ;
157- if (( GetFileType (StdHandlesInfo. ErrorHandle ) == FILE_TYPE_CHAR) &&
158- ( GetConsoleScreenBufferInfo (StdHandlesInfo. ErrorHandle , &ScreenBufferInfo)) )
71+ ConsoleInput::~ConsoleInput ()
72+ {
73+ if (m_Handle )
15974 {
160- IsConsoleError = TRUE ;
75+ TrySetConsoleMode (m_Handle, m_SavedMode);
76+ SetConsoleCP (m_SavedCodePage);
16177 }
162-
163- RestoreInputHandle.release ();
164- RestoreOutput.release ();
165- StdHandlesInfo.IsConsoleInput = IsConsoleInput;
166- StdHandlesInfo.IsConsoleOutput = IsConsoleOutput;
167- StdHandlesInfo.IsConsoleError = IsConsoleError;
168- StdHandlesInfo.SavedInputMode = SavedInputMode;
169- StdHandlesInfo.SavedOutputMode = SavedOutputMode;
170- StdHandlesInfo.SavedInputCP = SavedInputCP;
171- StdHandlesInfo.SavedOutputCP = SavedOutputCP;
17278}
173- } // namespace
17479
175- wsl::windows::common::SvcCommIo::SvcCommIo ()
80+ // ConsoleOutput implementation
81+ std::unique_ptr<ConsoleOutput> ConsoleOutput::Create ()
17682{
177- _stdHandlesInfo.InputHandle = GetStdHandle (STD_INPUT_HANDLE);
178- _stdHandlesInfo.OutputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
179- _stdHandlesInfo.ErrorHandle = GetStdHandle (STD_ERROR_HANDLE);
180- _stdHandlesInfo.ConsoleOutputHandle .reset (
83+ wil::unique_hfile ConsoleHandle (
18184 CreateFileW (L" CONOUT$" , GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr , OPEN_EXISTING, 0 , nullptr ));
18285
183- ConfigureStdHandles (_stdHandlesInfo);
184- _stdHandles.StdIn .HandleType = LxssHandleInput;
185- _stdHandles.StdIn .Handle = HandleToUlong (_stdHandlesInfo.InputHandle );
186- _stdHandles.StdOut .HandleType = LxssHandleOutput;
187- _stdHandles.StdOut .Handle = HandleToUlong (_stdHandlesInfo.OutputHandle );
188- _stdHandles.StdErr .HandleType = LxssHandleOutput;
189- _stdHandles.StdErr .Handle = HandleToUlong (_stdHandlesInfo.ErrorHandle );
190-
191- //
192- // N.B.: The console handle is not supposed to be closed, it is just copied
193- // from PEB.
194- //
195-
196- if (_stdHandlesInfo.IsConsoleInput )
86+ if (!ConsoleHandle)
19787 {
198- _stdHandles.StdIn .Handle = LXSS_HANDLE_USE_CONSOLE;
199- _stdHandles.StdIn .HandleType = LxssHandleConsole;
88+ return nullptr ;
20089 }
20190
202- if (_stdHandlesInfo.IsConsoleOutput )
91+ DWORD Mode;
92+ if (GetConsoleMode (ConsoleHandle.get (), &Mode))
20393 {
204- _stdHandles.StdOut .Handle = LXSS_HANDLE_USE_CONSOLE;
205- _stdHandles.StdOut .HandleType = LxssHandleConsole;
94+ return std::unique_ptr<ConsoleOutput>(new ConsoleOutput (std::move (ConsoleHandle), Mode));
20695 }
20796
208- if (_stdHandlesInfo.IsConsoleError )
209- {
210- _stdHandles.StdErr .Handle = LXSS_HANDLE_USE_CONSOLE;
211- _stdHandles.StdErr .HandleType = LxssHandleConsole;
212- }
97+ return nullptr ;
21398}
21499
215- wsl::windows::common::SvcCommIo::~SvcCommIo ()
100+ ConsoleOutput::ConsoleOutput (wil::unique_hfile ConsoleHandle, DWORD SavedMode) :
101+ m_ConsoleHandle (std::move(ConsoleHandle)), m_SavedMode(SavedMode)
216102{
217- try
103+ // Save code page
104+ m_SavedCodePage = GetConsoleOutputCP ();
105+
106+ // Configure for VT output with DISABLE_NEWLINE_AUTO_RETURN
107+ DWORD NewMode = m_SavedMode;
108+ WI_SetAllFlags (NewMode, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN);
109+
110+ // Try with DISABLE_NEWLINE_AUTO_RETURN first, fall back without it if not supported
111+ if (!SetConsoleMode (m_ConsoleHandle.get (), NewMode))
218112 {
219- RestoreConsoleMode ();
113+ WI_ClearFlag (NewMode, DISABLE_NEWLINE_AUTO_RETURN);
114+ TrySetConsoleMode (m_ConsoleHandle.get (), NewMode);
220115 }
221- CATCH_LOG ()
222- }
223116
224- PLXSS_STD_HANDLES
225- wsl::windows::common::SvcCommIo::GetStdHandles ()
226- {
227- return &_stdHandles;
117+ // Set UTF-8 code page
118+ SetConsoleOutputCP (CP_UTF8);
228119}
229120
230- COORD
231- wsl::windows::common::SvcCommIo::GetWindowSize () const
121+ ConsoleOutput::~ConsoleOutput ()
232122{
233- CONSOLE_SCREEN_BUFFER_INFOEX Info{};
234- Info.cbSize = sizeof (Info);
235- if (_stdHandlesInfo.IsConsoleOutput )
123+ if (m_ConsoleHandle)
236124 {
237- THROW_IF_WIN32_BOOL_FALSE (::GetConsoleScreenBufferInfoEx (_stdHandlesInfo.OutputHandle , &Info));
125+ TrySetConsoleMode (m_ConsoleHandle.get (), m_SavedMode);
126+ SetConsoleOutputCP (m_SavedCodePage);
238127 }
239- else if (_stdHandlesInfo.IsConsoleError )
240- {
241- THROW_IF_WIN32_BOOL_FALSE (::GetConsoleScreenBufferInfoEx (_stdHandlesInfo.ErrorHandle , &Info));
242- }
243-
244- return {
245- static_cast <short >(Info.srWindow .Right - Info.srWindow .Left + 1 ), static_cast <short >(Info.srWindow .Bottom - Info.srWindow .Top + 1 )};
246128}
247129
248- void wsl::windows::common::SvcCommIo::RestoreConsoleMode () const
249-
250- /* ++
251-
252- Routine Description:
130+ // SvcCommIo implementation
131+ SvcCommIo::SvcCommIo ()
132+ {
133+ const HANDLE InputHandle = GetStdHandle (STD_INPUT_HANDLE);
134+ const HANDLE OutputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
135+ const HANDLE ErrorHandle = GetStdHandle (STD_ERROR_HANDLE);
253136
254- Restores the saved input/output console mode.
137+ // Configure input console
138+ m_ConsoleInput = ConsoleInput::Create (InputHandle);
255139
256- Arguments:
140+ // Configure output console
141+ m_ConsoleOutput = ConsoleOutput::Create ();
257142
258- None.
143+ // Initialize the standard handles structure
144+ const bool IsConsoleInput = m_ConsoleInput != nullptr ;
145+ m_StdHandles.StdIn .HandleType = IsConsoleInput ? LxssHandleConsole : LxssHandleInput;
146+ m_StdHandles.StdIn .Handle = IsConsoleInput ? LXSS_HANDLE_USE_CONSOLE : HandleToUlong (InputHandle);
259147
260- Return Value:
148+ const bool IsConsoleOutput = IsConsoleHandle (OutputHandle);
149+ m_StdHandles.StdOut .HandleType = IsConsoleOutput ? LxssHandleConsole : LxssHandleOutput;
150+ m_StdHandles.StdOut .Handle = IsConsoleOutput ? LXSS_HANDLE_USE_CONSOLE : HandleToUlong (OutputHandle);
261151
262- None.
152+ const bool IsConsoleError = IsConsoleHandle (ErrorHandle);
153+ m_StdHandles.StdErr .HandleType = IsConsoleError ? LxssHandleConsole : LxssHandleOutput;
154+ m_StdHandles.StdErr .Handle = IsConsoleError ? LXSS_HANDLE_USE_CONSOLE : HandleToUlong (ErrorHandle);
263155
264- --*/
156+ // Cache a console handle for GetWindowSize
157+ m_WindowSizeHandle = IsConsoleOutput ? OutputHandle : (IsConsoleError ? ErrorHandle : nullptr );
158+ }
265159
160+ PLXSS_STD_HANDLES
161+ SvcCommIo::GetStdHandles ()
266162{
267- //
268- // Restore the console input and output modes.
269- //
163+ return &m_StdHandles;
164+ }
270165
271- if (_stdHandlesInfo.ConsoleOutputHandle )
166+ COORD
167+ SvcCommIo::GetWindowSize () const
168+ {
169+ if (m_WindowSizeHandle)
272170 {
273- ChangeConsoleMode (_stdHandlesInfo.ConsoleOutputHandle .get (), _stdHandlesInfo.SavedOutputMode );
274- SetConsoleOutputCP (_stdHandlesInfo.SavedOutputCP );
171+ CONSOLE_SCREEN_BUFFER_INFOEX Info{};
172+ Info.cbSize = sizeof (Info);
173+ THROW_IF_WIN32_BOOL_FALSE (GetConsoleScreenBufferInfoEx (m_WindowSizeHandle, &Info));
174+ return {
175+ static_cast <short >(Info.srWindow .Right - Info.srWindow .Left + 1 ),
176+ static_cast <short >(Info.srWindow .Bottom - Info.srWindow .Top + 1 )};
275177 }
276178
277- if (_stdHandlesInfo.IsConsoleInput != FALSE )
278- {
279- ChangeConsoleMode (_stdHandlesInfo.InputHandle , _stdHandlesInfo.SavedInputMode );
280- SetConsoleCP (_stdHandlesInfo.SavedInputCP );
281- }
179+ return {80 , 24 }; // Default size if no console
282180}
181+
182+ } // namespace wsl::windows::common
0 commit comments