microsoft / microsoft/terminal
conhost: SetConsoleWindowInfo broken when used in alternate screen buffer
- Dominant language
- C++
- Stars
- 105k
- Forks
- 9.6k
- Avg merge
- 3d 17h
- Merged PRs (30d)
- 29
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
#include
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.
https://user-images.githubusercontent.com/7597319/184560547-bc2d3926-633a-4c9c-bdf6-15a4e9aac47d.mp4
1. When trying to increase the window size to the maximum size allowed according to `GetConsoleScreenBufferInfo`, `SetConsoleWindowInfo` returns 0 with the invalid parameters error code.
2. When trying to decrease the window size, `SetConsoleWindowInfo` returns 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.
Contributor guide
Research direction
Start by compiling and running the provided C++ reproduction on the specified Windows build, comparing SetConsoleWindowInfo behavior in the main and alternate screen buffers. Trace the conhost handling of alternate-buffer window resizing and determine the intended behavior for maximum and smaller window requests. Done means the behavior is corrected or explicitly defined and covered by an appropriate regression test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- cli, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100