GetConsoleScreenBufferInfoEx + SetConsoleScreenBufferInfoEx screws up the size #18847

Closed
opened 2026-01-31 06:26:08 +00:00 by claunia · 5 comments
Owner

Originally created by @alabuzhev on GitHub (Nov 8, 2022).

Windows Terminal version

1.16.2641.0

Windows build number

10.0.19044.2006

Other Software

No response

Steps to reproduce

  1. Compile the following little program:
#include <cassert>
#include <windows.h>

int main()
{
	for (;;)
	{
		const auto out = GetStdHandle(STD_OUTPUT_HANDLE);
		CONSOLE_SCREEN_BUFFER_INFOEX csbi{ sizeof(csbi) };

		if (!GetConsoleScreenBufferInfoEx(out, &csbi))
			assert(false);

		if (!SetConsoleScreenBufferInfoEx(out, &csbi))
			assert(false);

		system("pause");
	}
}
  1. Run it.
  2. Follow the instructions on the screen.

Expected Behavior

Nothing should happen, because nothing has been changed in the structure.

Actual Behavior

In conhost: the window size decreases on each iteration, eventually the window disappears.
In WT: the buffer size decreases on each iteration, eventually OpenConsole crashes.

More

The issue is not synthetic: CSBI allows to change other information than window/buffer sizes, e.g. the color palette (I know that OSC 4 exists).
If I am only changing the palette, I do not expect changes in the sizes.

Ironically, sequential SetConsoleScreenBufferSize + SetConsoleWindowInfo calls seem to work as expected:

#include <cassert>
#include <windows.h>

int main()
{
	for (;;)
	{
		const auto out = GetStdHandle(STD_OUTPUT_HANDLE);
		CONSOLE_SCREEN_BUFFER_INFOEX csbi{ sizeof(csbi) };

		if (!GetConsoleScreenBufferInfoEx(out, &csbi))
			assert(false);

		// These work fine in any order
		if (!SetConsoleScreenBufferSize(out, csbi.dwSize))
			assert(false);

		if (!SetConsoleWindowInfo(out, true, &csbi.srWindow))
			assert(false);

		system("pause");
	}
}
Originally created by @alabuzhev on GitHub (Nov 8, 2022). ### Windows Terminal version 1.16.2641.0 ### Windows build number 10.0.19044.2006 ### Other Software _No response_ ### Steps to reproduce 1. Compile the following little program: ```C++ #include <cassert> #include <windows.h> int main() { for (;;) { const auto out = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFOEX csbi{ sizeof(csbi) }; if (!GetConsoleScreenBufferInfoEx(out, &csbi)) assert(false); if (!SetConsoleScreenBufferInfoEx(out, &csbi)) assert(false); system("pause"); } } ``` 2. Run it. 3. Follow the instructions on the screen. ### Expected Behavior Nothing should happen, because nothing has been changed in the structure. ### Actual Behavior In conhost: the window size decreases on each iteration, eventually the window disappears. In WT: the buffer size decreases on each iteration, eventually OpenConsole crashes. ### More The issue is not synthetic: CSBI allows to change other information than window/buffer sizes, e.g. the color palette (I know that `OSC 4` exists). If I am only changing the palette, I do not expect changes in the sizes. Ironically, sequential `SetConsoleScreenBufferSize` + `SetConsoleWindowInfo` calls seem to work as expected: ```C++ #include <cassert> #include <windows.h> int main() { for (;;) { const auto out = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFOEX csbi{ sizeof(csbi) }; if (!GetConsoleScreenBufferInfoEx(out, &csbi)) assert(false); // These work fine in any order if (!SetConsoleScreenBufferSize(out, csbi.dwSize)) assert(false); if (!SetConsoleWindowInfo(out, true, &csbi.srWindow)) assert(false); system("pause"); } } ```
claunia added the Product-ConhostResolution-By-DesignIssue-BugArea-Server labels 2026-01-31 06:26:09 +00:00
Author
Owner

@zadjii-msft commented on GitHub (Nov 8, 2022):

similarly: #3698

@zadjii-msft commented on GitHub (Nov 8, 2022): similarly: #3698
Author
Owner

@j4james commented on GitHub (Nov 8, 2022):

I'm assuming the size change is an expected behavior of the API at this point, given that it's been like that since forever, and people have just learned to work around it (see for example https://stackoverflow.com/a/52227764). It really should be documented somewhere though, if it isn't already.

The crash is another matter.

@j4james commented on GitHub (Nov 8, 2022): I'm assuming the size change is an expected behavior of the API at this point, given that it's been like that since forever, and people have just learned to work around it (see for example https://stackoverflow.com/a/52227764). It really should be documented somewhere though, if it isn't already. The crash is another matter.
Author
Owner

@alabuzhev commented on GitHub (Nov 8, 2022):

It should be possible to address this in a backward-compatible manner:

  • if the specified buffer & window sizes are exactly the same as the current ones, just do nothing and process other fields only
  • otherwise (incremented bottom & right as in that SO answer or anything else) use the current logic.
@alabuzhev commented on GitHub (Nov 8, 2022): It should be possible to address this in a backward-compatible manner: - if the specified buffer & window sizes are *exactly the same* as the current ones, just do nothing and process other fields only - otherwise (incremented bottom & right as in that SO answer or anything else) use the current logic.
Author
Owner

@j4james commented on GitHub (Nov 9, 2022):

if the specified buffer & window sizes are exactly the same as the current ones, just do nothing and process other fields only

I was going to say this sounds like a good idea, but I'm having second thoughts now. With the existing behavior, it's easy enough to explain that the GetConsoleScreenBufferInfoEx returns an inclusive rect, while SetConsoleScreenBufferInfoEx expects an exclusive rect. But having the interpretation of the coordinates change depending on the current value becomes a lot more problematic.

For one thing, you can't reliably call SetConsoleScreenBufferInfoEx without first calling GetConsoleScreenBufferInfoEx, because you can't know how the size will interpreted without knowing the current size. And then if you are actually trying to set the size to something exactly 1 cell smaller in both dimensions, you have to do that with two separate calls, otherwise the size change will be ignored.

And even if you don't care about those issues, in order for you to take advantage of the new behavior, you've either got to assume that all your users are using a recent version of Windows, or your code now has to have a version check, and a fallback that is capable of handling the previous behavior anyway. It's just creating more work for app devs.

@j4james commented on GitHub (Nov 9, 2022): > if the specified buffer & window sizes are exactly the same as the current ones, just do nothing and process other fields only I was going to say this sounds like a good idea, but I'm having second thoughts now. With the existing behavior, it's easy enough to explain that the `GetConsoleScreenBufferInfoEx` returns an inclusive rect, while `SetConsoleScreenBufferInfoEx` expects an exclusive rect. But having the interpretation of the coordinates change depending on the current value becomes a lot more problematic. For one thing, you can't reliably call `SetConsoleScreenBufferInfoEx` without first calling `GetConsoleScreenBufferInfoEx`, because you can't know how the size will interpreted without knowing the current size. And then if you are actually trying to set the size to something exactly 1 cell smaller in both dimensions, you have to do that with two separate calls, otherwise the size change will be ignored. And even if you don't care about those issues, in order for you to take advantage of the new behavior, you've either got to assume that all your users are using a recent version of Windows, or your code now has to have a version check, and a fallback that is capable of handling the previous behavior anyway. It's just creating more work for app devs.
Author
Owner

@carlos-zamora commented on GitHub (Feb 13, 2023):

Sure is. For compatibility purposes, this isn't really something we can fix, unfortunately. Thus, closing.

@carlos-zamora commented on GitHub (Feb 13, 2023): Sure is. For compatibility purposes, this isn't really something we can fix, unfortunately. Thus, closing.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#18847