You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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, &currentInfoEx) == 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();
}

关键修改点

  1. 恢复屏幕缓冲区大小的设置:必须将dwSize设置为目标窗口尺寸,确保缓冲区能容纳窗口显示内容
  2. 窗口区域从(0,0)开始:避免因原窗口位置偏移导致的尺寸计算错误
  3. 增加尺寸合法性检查:确保目标尺寸不超过系统返回的dwMaximumWindowSize,避免修改失败

补充说明

如果需要仅调整窗口大小而不改变缓冲区尺寸,可先将缓冲区设置为足够大的值,再调整窗口区域,之后再按需缩小缓冲区(需确保缓冲区不小于窗口区域)。

内容的提问来源于stack exchange,提问作者user3314691

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 08:40:25