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

Windows 10强制立即重绘后窗口调整大小卡顿问题

Windows 10强制立即重绘导致窗口调整大小异常的问题解析与解决方案

问题1:为什么会出现调整大小卡住的情况?

Windows窗口调整大小由系统的模态消息循环处理:当你拖动窗口边框时,系统会接管消息处理,持续响应鼠标移动来调整窗口尺寸,直到捕获到WM_LBUTTONUP(鼠标释放)才退出这个循环。

而使用RDW_INVALIDATE | RDW_UPDATENOW或者UpdateWindow()时,会强制立即同步执行重绘——这会打断系统的模态循环,抢占消息处理优先级,导致系统无法及时接收和处理鼠标释放等关键消息。同时主循环每一轮都调用立即重绘,会持续压制系统的调整大小相关消息,窗口始终认为用户还在拖动,因此卡在调整模式,甚至ESC键的消息也得不到处理。

对比RDW_INTERNALPAINT:它只是标记窗口需要重绘,将WM_PAINT加入消息队列,不会立即执行重绘,系统的模态循环可以正常处理鼠标消息,所以调整大小行为正常。

问题2:如何在强制立即重绘的同时保持正常的调整大小行为?

可以通过检测窗口是否处于调整/移动状态,动态切换重绘策略:

  1. 在窗口过程中监听WM_ENTERSIZEMOVE和WM_EXITSIZEMOVE消息,记录当前是否处于调整大小或移动窗口的状态。
  2. 主循环里根据这个状态选择重绘方式:非调整状态下用立即重绘,调整状态下改用异步重绘,避免干扰系统的模态循环。

修改后的示例代码:

// clang -std=c23 -o win_resize_stuck.exe -luser32 -lgdi32 ./win_resize_stuck.c

#include <stdio.h>
#include <assert.h>
#include <string.h>

#include <windows.h>
#include <windowsx.h>

static BOOL is_resizing = FALSE; // 标记是否处于窗口调整/移动状态

static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_CREATE:
            break;
        case WM_CLOSE:
            PostQuitMessage(0);
            break;
        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // 这里添加你的重绘逻辑,比如绘制背景或内容
            EndPaint(hWnd, &ps);
            break;
        }
        case WM_ENTERSIZEMOVE:
            is_resizing = TRUE; // 进入调整/移动状态
            break;
        case WM_EXITSIZEMOVE:
            is_resizing = FALSE; // 退出调整/移动状态
            break;
        default:
            break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

HWND window;
#define WIN_CLASS_NAME "tmp"
#define APP_NAME "tmp"

static void create_window() {
    WNDCLASSEX win_class;
    win_class.cbSize = sizeof(WNDCLASSEX);
    win_class.style = CS_HREDRAW | CS_VREDRAW;
    win_class.lpfnWndProc = WndProc;
    win_class.cbClsExtra = 0;
    win_class.cbWndExtra = 0;
    win_class.hInstance = GetModuleHandle(NULL);
    win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
    win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    win_class.lpszMenuName = NULL;
    win_class.lpszClassName = WIN_CLASS_NAME;
    win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
    if (!RegisterClassEx(&win_class)) {
        fprintf(stderr, "Unexpected error trying to start the application!\n");
        fflush(stderr);
        exit(1);
    }
    RECT wr = {0, 0, 500, 500};
    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
    window = CreateWindowEx(0,
                            WIN_CLASS_NAME,
                            APP_NAME,
                            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU,
                            100, 100,
                            wr.right - wr.left,
                            wr.bottom - wr.top,
                            NULL,
                            NULL,
                            GetModuleHandle(NULL),
                            NULL);
}

int main(int argc, const char** argv) {
    (void)argc;
    (void)argv;

    create_window();

    MSG msg;
    BOOL done = FALSE;
    while (!done) {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) {
                done = TRUE;
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        // 根据窗口状态选择重绘方式
        if (is_resizing) {
            // 调整状态下用异步重绘,不干扰系统循环
            RedrawWindow(window, NULL, NULL, RDW_INTERNALPAINT);
        } else {
            // 非调整状态下强制立即重绘
            RedrawWindow(window, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
        }
    }
    return 0;
}

关键说明:

  • WM_ENTERSIZEMOVE:当用户开始拖动窗口边框或标题栏时触发,标记窗口进入调整/移动状态。
  • WM_EXITSIZEMOVE:当用户释放鼠标,结束调整/移动时触发,取消标记。
  • 主循环优先处理完所有消息再执行重绘,避免消息堆积;同时根据状态切换重绘策略,既满足立即重绘的需求,又不干扰系统的调整大小逻辑。

另外,WM_PAINT中必须调用BeginPaint和EndPaint,否则系统会持续发送WM_PAINT消息,造成额外性能开销。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:29:59