Repository navigation
Open
Labels
Area-ServerDown in the muck of API call servicing, interprocess communication, eventing, etc.Down in the muck of API call servicing, interprocess communication, eventing, etc.Issue-BugIt either shouldn't be doing this or needs an investigation.It either shouldn't be doing this or needs an investigation.Product-ConhostFor issues in the Console codebaseFor issues in the Console codebase
Milestone
Description
Windows Terminal version
No response
Windows build number
10.0.19041.1806
Other Software
conhost.exe 10.0.19041.1566
conhostV1.dll 10.0.19041.21
Visual Studio 2019 version 16.11.18
Steps to reproduce
Use this test program:
#include <windows.h>
#include <iostream>
bool get_info_and_print(HANDLE h_stdout, CONSOLE_SCREEN_BUFFER_INFO& buf_info)
{
if (!GetConsoleScreenBufferInfo(h_stdout, &buf_info)) {
std::cerr << "Failed to get screen buffer info.\n";
return false;
}
std::cout << "Screen buffer size: "
<< buf_info.dwSize.X << "x" << buf_info.dwSize.Y << "\n";
std::cout << "Window size: "
<< buf_info.srWindow.Right + 1 - buf_info.srWindow.Left << "x"
<< buf_info.srWindow.Bottom + 1 - buf_info.srWindow.Top << "\n\n";
std::cin.get();
return true;
}
// Set screen buffer size, then set the window size to maximum.
// Revert back to original window size and buffer size afterward.
// Assume initial console size is smaller than 150x45, larger than 10x10
bool do_test()
{
constexpr COORD target_buffer_size{ 150, 45 };
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (h_stdout == INVALID_HANDLE_VALUE) return 1;
std::cout << "Orignial buffer & window\n";
// Get original screen buffer info
CONSOLE_SCREEN_BUFFER_INFO original_buf_info;
if (!get_info_and_print(h_stdout, original_buf_info)) return false;
// Set the screen buffer to target size
if (!SetConsoleScreenBufferSize(h_stdout, target_buffer_size)) {
std::cerr << "Failed to set buffer size.\n";
}
std::cout << "Made buffer larger\n";
// Get buffer info after adjustment
CONSOLE_SCREEN_BUFFER_INFO larger_buf_info;
if (!get_info_and_print(h_stdout, larger_buf_info)) return false;
std::cout << "GetConsoleScreenBufferInfo gives dwMaximumWindowSize as "
<< larger_buf_info.dwMaximumWindowSize.X << "x"
<< larger_buf_info.dwMaximumWindowSize.Y << "!\n";
// Attempt to set window size to maximum allowed.
SMALL_RECT larger_window_size{
0, 0,
larger_buf_info.dwMaximumWindowSize.X - 1,
larger_buf_info.dwMaximumWindowSize.Y - 1
};
// ################################################################
// THIS FAILS IN ALT BUFFER WITH ERROR_INVALID_PARAMETER DESPITE
// ADHERING TO THE PARAMETER LIMITS GIVEN BY ConsoleScreenBufferInfo
if (!SetConsoleWindowInfo(h_stdout, TRUE, &larger_window_size)) {
DWORD err_code = GetLastError();
std::cerr << "Failed to set window size. Err code: " << err_code << "\n";
}
std::cout << "Also made window larger\n";
// Get buffer info after adjustment
CONSOLE_SCREEN_BUFFER_INFO larger_buf_info_temp;
if (!get_info_and_print(h_stdout, larger_buf_info_temp)) return false;
// Revert window
if (!SetConsoleWindowInfo(h_stdout, TRUE, &original_buf_info.srWindow)) {
std::cerr << "Failed to revert window size\n";
}
if (!SetConsoleScreenBufferSize(h_stdout, original_buf_info.dwSize)) {
std::cerr << "Failed to revert screen buffer size\n";
}
// Attempt to make the window size smaller than the original size
SMALL_RECT smaller_window_size {
original_buf_info.srWindow.Left,
original_buf_info.srWindow.Top,
original_buf_info.srWindow.Right - 10,
original_buf_info.srWindow.Bottom - 10
};
// ################################################################
// THIS FAILS IN ALT BUFFER BUT RETURNS NONZERO (SUCCESS)
if (!SetConsoleWindowInfo(h_stdout, TRUE, &smaller_window_size)) {
DWORD err_code = GetLastError();
std::cerr << "Failed to set window size. Err code: " << err_code << "\n";
}
std::cout << "Made window smaller\n";
// Get buffer info after adjustment
CONSOLE_SCREEN_BUFFER_INFO smaller_buf_info_temp;
if (!get_info_and_print(h_stdout, smaller_buf_info_temp)) return false;
// Revert window
if (!SetConsoleWindowInfo(h_stdout, TRUE, &original_buf_info.srWindow)) {
std::cerr << "Failed to revert window size\n";
}
return true;
}
int main()
{
// Attempt to enable virtual terminal prcessing
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (h_stdout == INVALID_HANDLE_VALUE) return 1;
DWORD stdout_mode;
if (!GetConsoleMode(h_stdout, &stdout_mode)) return 1;
if (!SetConsoleMode(h_stdout, stdout_mode |
ENABLE_VIRTUAL_TERMINAL_PROCESSING |
ENABLE_PROCESSED_OUTPUT))
{
return 1;
}
std::cout << "Testing on main screen buffer.\n";
do_test();
// Switch to alternate screen buffer
std::cout << "\x1b[?1049h" << std::flush;
std::cout << "Testing on alternate screen buffer.\n";
do_test();
// Switch back to main screen buffer
std::cout << "\x1b[?1049l" << std::flush;
// Restore console mode
SetConsoleMode(h_stdout, stdout_mode);
return 0;
}
Expected Behavior
No response
Actual Behavior
Recording compiled with Visual Studio 2019 version 16.11.18, default console project with Debug/x86 target.
rqUpmv2sfr.mp4
- When trying to increase the window size to the maximum size allowed according to
GetConsoleScreenBufferInfo,SetConsoleWindowInforeturns 0 with the invalid parameters error code. - When trying to decrease the window size,
SetConsoleWindowInforeturns non-zero indicating success, but the actual window size remains unchanged.
I don't know if resizing is ever supposed to work in the alternate screen buffer, but even if it's supposed to fail, the way it fails seems pretty nonsensical to me.
Metadata
Metadata
Assignees
Labels
Area-ServerDown in the muck of API call servicing, interprocess communication, eventing, etc.Down in the muck of API call servicing, interprocess communication, eventing, etc.Issue-BugIt either shouldn't be doing this or needs an investigation.It either shouldn't be doing this or needs an investigation.Product-ConhostFor issues in the Console codebaseFor issues in the Console codebase
Activity
Gyross commentedon Aug 15, 2022
As an aside, can you explain the behaviour of the scrollbars?
Is all this just conhost only being able to halfway enforce the buffer size == window size rule for alt buffer?
BDisp commentedon Aug 8, 2023
The limitation of Windows Terminal being ignoring the
SetConsoleScreenBufferSizeto resize the buffer to the windows size is killing me. Forces the WT showing the vertical scroll bar when we don't want it. Please can someone explains why we can't resize the buffer to the same size of the visible window, when our app handles the available space? Due the others tabs? Each tab must have is own buffer size and not depends of the WT window size.zadjii-msft commentedon Aug 9, 2023
What you're describing sounds more like #5094. This is specifically a bug in resizing the alt buffer withSetConsoleWindowInfoin conhost.er, wait though, is it? It sounds like you're trying to use
SetConsoleScreenBufferSizeto get rid of the scrollback, in terminal? Why wouldn't you just use the alt buffer then? (this may warrant a new discussion thread)BDisp commentedon Aug 9, 2023
Mike Griese (@zadjii-msft) thanks for your feedback. Yes you are right it's more like #5094 and you'll see some comments I posted there. I don't have any issue by resizing the windows and the buffer with the same size with
conhost. The trick is first resizing the buffer with theSetConsoleScreenBufferInfoEx(ScreenBuffer, ref csbi)method and then resizing the window with theSetConsoleWindowInfo(OutputHandle, true, ref winRect)method. Finally I call theSetConsoleScreenBufferInfoEx (ScreenBuffer, ref csbi)again. This only work because I use two separate handles, one for the window size (OutputHandle) and other for the buffer size (ScreenBuffer). If we use the same handle for both it will throw an exception, of course, becauseconhostuses the same handle.I only want to get rid the scrollback while my app is running but when I exit I restore the saved original back. What do you mean by using the alt buffer?
Resizing the buffer with Win API console app using conhost, cmd, powershell, conemu works well, but not on
Windows Terminal. The only workaround that works on WT is using"\x1b[3J"escape sequence, but it shouldn't being necessary.zadjii-msft commentedon Aug 9, 2023
Oh that's like, literally the whole idea of the "alternate screen buffer"! That's the thing that apps like
vim,less,emacs,tmux, etc use to let them draw a full-window application, without a scrollback, and then dismiss it simply. Our docs are here. Basically, justSetConsoleModewithENABLE_VT_PROCESSING, then print a"\x1b[?1049h"to enter the alt buffer, and exit it with"\x1b[?1049l". Pretty sure this sample (extremely dated) has an example of using the alt buffer from a c++ app.BDisp commentedon Aug 9, 2023
Thanks for your attention. That was what I did for the NetDriver that essential use .NET
System.Consolefor cross platform where forWindowsI use Win API withENABLE_VT_PROCESSINGonly for accepting escape sequences for keystrokes/mouse handle and forLinuxis more straight way. OnWindowsit's very slower than onLinux. Only for Windows we have a WindowsDriver which basically use native Win API for keystroke/mouse handle, which is much more faster. Since it doesn't usesENABLE_VT_PROCESSINGonlyWindows Terminalrecognizes escape sequences but not other terminal, which only recognize Win API. IfWindows Terminalallows Win API functions on a Windows environment would be great. Believe me, conhost, cmd, powershell take a long time to interpret escape sequence, mainly with the mouse.BDisp commentedon Nov 5, 2024
Thanks to the Leonard Hecker (@lhecker), I finally learned how to appropriate use during app execution the screen buffer size always equal to the window size, by his words in #18148 (comment).
Generally speaking: Do not ever resize the buffer because the window was resized. This is true without the alternate screen-buffer but it's especially true if you do use it.So, if we want to using the screen buffer size different of the window size, then we shouldn't ever use the alternate screen-buffer (ASB) at all.