Original console buffer is not restored when closing a secondary one #22178

Open
opened 2026-01-31 08:05:38 +00:00 by claunia · 0 comments
Owner

Originally created by @avih on GitHub (Aug 28, 2024).

Originally assigned to: @lhecker on GitHub.

Windows Terminal version

1.22.240823002-preview

Windows build number

10.0.19045

Other Software

No response

Steps to reproduce

Reduced test code (by lhecker):

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

int main() {
    const auto buffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, nullptr, CONSOLE_TEXTMODE_BUFFER, nullptr);
    SetConsoleActiveScreenBuffer(buffer);
    CloseHandle(buffer);
    return 0;
}

Run a program which creates and activates a new console screen buffer using CreateConsoleScreenBuffer and SetConsoleActiveScreenBuffer.

The following C program with argument value 0-4 does all combos:

// usage: *argv 0|1|2|3|4
// create+activate new screen buffer, print a message to it, sleep 1s, then before exit:
//   0: do nothing.
//   1: CloseHandle(newbuf).
//   2: SetConsoleActiveScreenBuffer(orig_con)
//   3: CloseHandle(newbuf), SetConsoleActiveScreenBuffer(orig_con)
//   4: SetConsoleActiveScreenBuffer(orig_con), CloseHandle(newbuf)
newbuf.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>


#define writecon(h, s) WriteConsole(h, (s), strlen(s), 0, 0)
#define ERR_EXIT(...) (fprintf(stderr, __VA_ARGS__), exit(1), 0)

// usage: *argv 0|1|2|3|4
// create+activate new screen buffer, print a message to it, sleep 1s, then before exit:
//   0: do nothing.
//   1: CloseHandle(newbuf).
//   2: SetConsoleActiveScreenBuffer(orig_con)
//   3: CloseHandle(newbuf), SetConsoleActiveScreenBuffer(orig_con)
//   4: SetConsoleActiveScreenBuffer(orig_con), CloseHandle(newbuf)

int main(int argc, char **argv)
{
	int mode = argc > 1 ? atoi(argv[1]) : 0;

	HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE);
	if (hcon == INVALID_HANDLE_VALUE)
		ERR_EXIT("can't get stdout handle\n");

	if (!writecon(hcon, "orig screen buffer\n"))
		ERR_EXIT("can't write to stdout console\n");

	HANDLE hnewbuf = CreateConsoleScreenBuffer(
		GENERIC_WRITE, FILE_SHARE_WRITE,
		0, CONSOLE_TEXTMODE_BUFFER, 0);
	if (hnewbuf == INVALID_HANDLE_VALUE)
		ERR_EXIT("can't create new screen buf\n");

	if (!SetConsoleActiveScreenBuffer(hnewbuf))
		ERR_EXIT("can't activete new screen buf\n");

	if (!writecon(hnewbuf, "new screen buffer\n"))
		ERR_EXIT("can't write to new screen buf\n");

	Sleep(1000);

	// all combos of "close new buf" and "restore orig buff", + reverse order.
	//
	// expected result:
	// - all combos restore the original buf on exit (maybe implicitly)
	//
	// actual result:
	// - Working as expected in conhost.exe or OpenConsole.exe (including 1.22)
	//   or Windows Terminal (up to and including 1.21).
	//
	// - in Windows Terminal 1.22: only 2 and 4 work as expected
	//   ("restore orig buf" without or before "close new buf")
	//   - 0: no close and no manual restore: not restored.
	//   - 1: close only: not restored.
	//   - 3: close and restored manually: not restored.

	switch (mode) {
		case 0:
			break;

		case 1:
			CloseHandle(hnewbuf);
			break;

		case 2:
			if (!SetConsoleActiveScreenBuffer(hcon))
				ERR_EXIT("can't restore orig screen buf\n");
			break;

		case 3:
			CloseHandle(hnewbuf);
			if (!SetConsoleActiveScreenBuffer(hcon))
				ERR_EXIT("can't restore orig screen buf\n");
			break;

		case 4:  // like 3 but in reverse order
			if (!SetConsoleActiveScreenBuffer(hcon))
				ERR_EXIT("can't restore orig screen buf\n");
			CloseHandle(hnewbuf);
			break;
	}

	return 0;
}

Expected Behavior

Original screen buffer is restored when the application exits (its content and original cursor position), regardless if the new screen buffer handle is closed or not, and regardless if the original screen buffer is re-activated before exit.

Actual Behavior

No issue in conhost.exe or OpenConsole.exe (even of 1.22), or Windows terminal up to and including 1.21.

With Windows terminal 1.22 (preview):

  • The original screen buffer is only restored if SetConsoleActiveScreenBuffer(orig_con) is invoked without or before CloseHandle(h_newbuf).
  • Specifically, it's not restored if:
    • Neither CloseHandle nor SetConsoleActiveScreenBuffer(orig_con) are used.
    • Only CloseHandle is used.
    • Both CloseHandle and SetConsoleActiveScreenBuffer(orig_con) are used in that order.
Originally created by @avih on GitHub (Aug 28, 2024). Originally assigned to: @lhecker on GitHub. ### Windows Terminal version 1.22.240823002-preview ### Windows build number 10.0.19045 ### Other Software _No response_ ### Steps to reproduce Reduced test code (by lhecker): ```cpp #define WIN32_LEAN_AND_MEAN #include <Windows.h> int main() { const auto buffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, nullptr, CONSOLE_TEXTMODE_BUFFER, nullptr); SetConsoleActiveScreenBuffer(buffer); CloseHandle(buffer); return 0; } ``` --- Run a program which creates and activates a new console screen buffer using `CreateConsoleScreenBuffer` and `SetConsoleActiveScreenBuffer`. The following C program with argument value 0-4 does all combos: ``` // usage: *argv 0|1|2|3|4 // create+activate new screen buffer, print a message to it, sleep 1s, then before exit: // 0: do nothing. // 1: CloseHandle(newbuf). // 2: SetConsoleActiveScreenBuffer(orig_con) // 3: CloseHandle(newbuf), SetConsoleActiveScreenBuffer(orig_con) // 4: SetConsoleActiveScreenBuffer(orig_con), CloseHandle(newbuf) ``` <details> <summary>newbuf.c</summary> ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <windows.h> #define writecon(h, s) WriteConsole(h, (s), strlen(s), 0, 0) #define ERR_EXIT(...) (fprintf(stderr, __VA_ARGS__), exit(1), 0) // usage: *argv 0|1|2|3|4 // create+activate new screen buffer, print a message to it, sleep 1s, then before exit: // 0: do nothing. // 1: CloseHandle(newbuf). // 2: SetConsoleActiveScreenBuffer(orig_con) // 3: CloseHandle(newbuf), SetConsoleActiveScreenBuffer(orig_con) // 4: SetConsoleActiveScreenBuffer(orig_con), CloseHandle(newbuf) int main(int argc, char **argv) { int mode = argc > 1 ? atoi(argv[1]) : 0; HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE); if (hcon == INVALID_HANDLE_VALUE) ERR_EXIT("can't get stdout handle\n"); if (!writecon(hcon, "orig screen buffer\n")) ERR_EXIT("can't write to stdout console\n"); HANDLE hnewbuf = CreateConsoleScreenBuffer( GENERIC_WRITE, FILE_SHARE_WRITE, 0, CONSOLE_TEXTMODE_BUFFER, 0); if (hnewbuf == INVALID_HANDLE_VALUE) ERR_EXIT("can't create new screen buf\n"); if (!SetConsoleActiveScreenBuffer(hnewbuf)) ERR_EXIT("can't activete new screen buf\n"); if (!writecon(hnewbuf, "new screen buffer\n")) ERR_EXIT("can't write to new screen buf\n"); Sleep(1000); // all combos of "close new buf" and "restore orig buff", + reverse order. // // expected result: // - all combos restore the original buf on exit (maybe implicitly) // // actual result: // - Working as expected in conhost.exe or OpenConsole.exe (including 1.22) // or Windows Terminal (up to and including 1.21). // // - in Windows Terminal 1.22: only 2 and 4 work as expected // ("restore orig buf" without or before "close new buf") // - 0: no close and no manual restore: not restored. // - 1: close only: not restored. // - 3: close and restored manually: not restored. switch (mode) { case 0: break; case 1: CloseHandle(hnewbuf); break; case 2: if (!SetConsoleActiveScreenBuffer(hcon)) ERR_EXIT("can't restore orig screen buf\n"); break; case 3: CloseHandle(hnewbuf); if (!SetConsoleActiveScreenBuffer(hcon)) ERR_EXIT("can't restore orig screen buf\n"); break; case 4: // like 3 but in reverse order if (!SetConsoleActiveScreenBuffer(hcon)) ERR_EXIT("can't restore orig screen buf\n"); CloseHandle(hnewbuf); break; } return 0; } ``` </details> ### Expected Behavior Original screen buffer is restored when the application exits (its content and original cursor position), regardless if the new screen buffer handle is closed or not, and regardless if the original screen buffer is re-activated before exit. ### Actual Behavior No issue in conhost.exe or OpenConsole.exe (even of 1.22), or Windows terminal up to and including 1.21. With Windows terminal 1.22 (preview): - The original screen buffer is only restored if `SetConsoleActiveScreenBuffer(orig_con)` is invoked without or before `CloseHandle(h_newbuf)`. - Specifically, it's not restored if: - Neither `CloseHandle` nor `SetConsoleActiveScreenBuffer(orig_con)` are used. - Only `CloseHandle` is used. - Both `CloseHandle` and `SetConsoleActiveScreenBuffer(orig_con)` are used in that order.
claunia added the Issue-BugIn-PRArea-VTNeeds-Tag-FixProduct-Conpty labels 2026-01-31 08:05:39 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#22178