Win11更新后SetConsoleScreenBufferInfoEx失效:Bug还是新特性?
Win11下SetConsoleScreenBufferInfoEx无法修改控制台窗口大小的解决办法
问题背景
Windows更新后,控制台程序调用SetConsoleScreenBufferInfoEx()无法修改窗口大小。相同的EXE文件在旧版Win10设备上可正常修改窗口尺寸,但在更新后的Win11设备上完全无变化。
测试代码如下:
#include <stdio.h> #include <windows.h> //Returns the last Win32 error, in string format. Returns an empty string if there is no error. const char *GetLastErrorStr(DWORD errorMessageID) { #define BUFSIZ 100 static char buffer[BUFSIZ+1]; if(errorMessageID == 0) { return ""; //No error message has been recorded } LPSTR messageBuffer = NULL; size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); size_t s; if(size > BUFSIZ) { s = BUFSIZ; } else { s = size; } strncpy(buffer, messageBuffer, s); LocalFree(messageBuffer); return buffer; } int main(int argc, char *argv[]) { HANDLE co; HANDLE ci; DWORD gs = 0; DWORD ss = 0; CONSOLE_SCREEN_BUFFER_INFOEX currentInfoEx { sizeof currentInfoEx }; CONSOLE_SCREEN_BUFFER_INFOEX newInfoEx { sizeof newInfoEx }; COORD consiz; // Set the screen size we want consiz.X = 110; consiz.Y = 44; // Get streams co = GetStdHandle(STD_OUTPUT_HANDLE); ci = GetStdHandle(STD_INPUT_HANDLE); // Get screen info if(GetConsoleScreenBufferInfoEx(co, ¤tInfoEx) == 0) { gs = GetLastError(); } // Set screen info newInfoEx = currentInfoEx; //newInfoEx.dwSize.X = consiz.X; //newInfoEx.dwSize.Y = consiz.Y; newInfoEx.srWindow.Left = newInfoEx.srWindow.Left; newInfoEx.srWindow.Top = newInfoEx.srWindow.Top; newInfoEx.srWindow.Right = newInfoEx.srWindow.Left + consiz.X - 1; newInfoEx.srWindow.Bottom = newInfoEx.srWindow.Top + consiz.Y - 1; newInfoEx.wAttributes = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY; if(SetConsoleScreenBufferInfoEx(co, &newInfoEx) == 0) { ss = GetLastError(); } // Print results if(gs != 0) { printf("Get Screen Size error = %s\n", GetLastErrorStr(gs)); } if(ss != 0) { printf("Set Screen Size error = %s\n", GetLastErrorStr(ss)); } printf("Original - Size %d/%d Max %d/%d L/T R/B %d/%d %d/%d\n", currentInfoEx.dwSize.X, currentInfoEx.dwSize.Y, currentInfoEx.dwMaximumWindowSize.X, currentInfoEx.dwMaximumWindowSize.Y, currentInfoEx.srWindow.Left, currentInfoEx.srWindow.Top, currentInfoEx.srWindow.Right, currentInfoEx.srWindow.Bottom ); printf("New - Size %d/%d Max %d/%d L/T R/B %d/%d %d/%d\n", newInfoEx.dwSize.X, newInfoEx.dwSize.Y, newInfoEx.dwMaximumWindowSize.X, newInfoEx.dwMaximumWindowSize.Y, newInfoEx.srWindow.Left, newInfoEx.srWindow.Top, newInfoEx.srWindow.Right, newInfoEx.srWindow.Bottom ); // Wait for key printf("Press Enter : "); getchar(); return(0); }
原因分析
这不是Bug,而是Win11控制台的新特性限制。Win11整合Windows Terminal后,控制台的窗口管理逻辑发生了变化:仅修改窗口显示区域(srWindow)不会触发窗口大小变更,必须同步调整屏幕缓冲区的大小(dwSize),且缓冲区尺寸必须大于等于窗口显示区域的尺寸,否则修改请求会被静默忽略。
原代码中注释掉了dwSize的修改操作,这正是Win11下无效的核心原因。
修正方案
要在Win11上成功修改控制台窗口大小,需同步调整屏幕缓冲区和窗口显示区域,确保两者尺寸匹配且不超过系统限制。
修正后的核心代码片段:
// Set screen info newInfoEx = currentInfoEx; // 1. 先设置屏幕缓冲区大小为目标尺寸 newInfoEx.dwSize.X = consiz.X; newInfoEx.dwSize.Y = consiz.Y; // 2. 再调整窗口显示区域匹配目标尺寸 newInfoEx.srWindow.Left = 0; newInfoEx.srWindow.Top = 0; newInfoEx.srWindow.Right = consiz.X - 1; newInfoEx.srWindow.Bottom = consiz.Y - 1; newInfoEx.wAttributes = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY; // 额外检查:确保目标尺寸不超过系统允许的最大值 if (consiz.X > currentInfoEx.dwMaximumWindowSize.X || consiz.Y > currentInfoEx.dwMaximumWindowSize.Y) { printf("Target size exceeds system maximum!\n"); } if(SetConsoleScreenBufferInfoEx(co, &newInfoEx) == 0) { ss = GetLastError(); }
关键修改点
- 恢复屏幕缓冲区大小的设置:必须将
dwSize设置为目标窗口尺寸,确保缓冲区能容纳窗口显示内容 - 窗口区域从(0,0)开始:避免因原窗口位置偏移导致的尺寸计算错误
- 增加尺寸合法性检查:确保目标尺寸不超过系统返回的
dwMaximumWindowSize,避免修改失败
补充说明
如果需要仅调整窗口大小而不改变缓冲区尺寸,可先将缓冲区设置为足够大的值,再调整窗口区域,之后再按需缩小缓冲区(需确保缓冲区不小于窗口区域)。
内容的提问来源于stack exchange,提问作者user3314691
相关产品推荐
相关产品推荐

