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

Win32窗口正常与全屏切换异常:切换回正常模式故障求助

Win32窗口全屏切换回正常模式异常的原因分析

问题背景

我编写了一个Win32窗口全屏/正常模式切换函数:当宽度参数W为0时进入全屏模式,否则以指定宽高W、H切换到正常模式。全屏模式显示正常,但切换回正常模式时出现显示异常。

我先后尝试了以下几种实现方式,问题均未解决:

初始实现(MoveWindow版本)

// width equal 0 = fullscreen, other = normal window
void CL_fulscrn(HWND hwnd, const unsigned short W, const unsigned short H) {
    if (!W) {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, 0);
        SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
        MoveWindow(hwnd, 0, 0, GetDeviceCaps(GetDC(NULL), HORZRES), GetDeviceCaps(GetDC(NULL), VERTRES), 0);
    }
    else {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
        SetWindowLongPtr(hwnd, GWL_STYLE, WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME | WS_VISIBLE | WS_OVERLAPPED);
        MoveWindow(hwnd, (GetDeviceCaps(GetDC(NULL), HORZRES) - W) / 2, (GetDeviceCaps(GetDC(NULL), VERTRES) - H) / 2, W, H, 0);
    }
}

替换为SetWindowPos版本

// width equal 0 = fullscreen, other = normal window
void CL_fulscrn(HWND hwnd, const unsigned short W, const unsigned short H) {
    if (!W) {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, 0);
        SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
        SetWindowPos(hwnd, 0, 0, 0, GetDeviceCaps(GetDC(NULL), HORZRES), GetDeviceCaps(GetDC(NULL), VERTRES), SWP_NOZORDER);
    }
    else {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
        SetWindowLongPtr(hwnd, GWL_STYLE, WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME | WS_VISIBLE | WS_OVERLAPPED);
        SetWindowPos(hwnd, 0, (GetDeviceCaps(GetDC(NULL), HORZRES) - W) / 2, (GetDeviceCaps(GetDC(NULL), VERTRES) - H) / 2, W, H, SWP_NOZORDER);
    }
}

添加SWP_FRAMECHANGED参数版本

void CL_fulscrn(HWND hwnd, const unsigned short W, const unsigned short H) {
    if (!W) {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, 0);
        SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
        // I tried this too, and same problem
        //SetWindowPos(hwnd, NULL, 0, 0, GetDeviceCaps(GetDC(NULL), HORZRES), GetDeviceCaps(GetDC(NULL), VERTRES), SWP_FRAMECHANGED | SWP_NOZORDER);
         SetWindowPos(hwnd, NULL, 0, 0, GetDeviceCaps(GetDC(NULL), HORZRES), GetDeviceCaps(GetDC(NULL), VERTRES), SWP_FRAMECHANGED);
    }
    else {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
        SetWindowLongPtr(hwnd, GWL_STYLE, WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME | WS_VISIBLE | WS_OVERLAPPED);
        // I tried this too, and same problem
        //SetWindowPos(hwnd, NULL, (GetDeviceCaps(GetDC(NULL), HORZRES) - W) / 2, (GetDeviceCaps(GetDC(NULL), VERTRES) - H) / 2, W, H, SWP_FRAMECHANGED | SWP_NOZORDER);
         SetWindowPos(hwnd, NULL, (GetDeviceCaps(GetDC(NULL), HORZRES) - W) / 2, (GetDeviceCaps(GetDC(NULL), VERTRES) - H) / 2, W, H, SWP_FRAMECHANGED);
    }
}

异常原因分析

  1. 窗口样式组合错误
    切换回正常模式时,手动组合的窗口样式缺少了WS_CAPTION(标题栏核心样式)。标准重叠窗口应使用WS_OVERLAPPEDWINDOW预定义组合样式,它包含WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU等所有必要的窗口框架样式,手动组合时遗漏关键样式会导致非客户区(标题栏、边框)绘制异常。

  2. GDI资源泄漏
    每次调用GetDC(NULL)获取屏幕DC后,未调用ReleaseDC(NULL, hdc)释放资源,长期运行会导致GDI资源耗尽,虽不是当前显示异常的直接原因,但属于必须修复的问题。

  3. 样式修改后的同步逻辑缺陷
    即使添加了SWP_FRAMECHANGED,若样式本身不正确,系统也无法正确刷新窗口框架。此外,直接覆盖原有窗口样式而非基于原有样式修改,可能丢失窗口创建时的默认附加样式,导致窗口显示异常。

修正后的示例代码

// width equal 0 = fullscreen, other = normal window
void CL_fulscrn(HWND hwnd, const unsigned short W, const unsigned short H) {
    HDC hdcScreen = GetDC(NULL);
    if (!hdcScreen) return;

    int screenWidth = GetDeviceCaps(hdcScreen, HORZRES);
    int screenHeight = GetDeviceCaps(hdcScreen, VERTRES);
    ReleaseDC(NULL, hdcScreen); // 释放DC资源,避免泄漏

    if (!W) {
        // 切换全屏:使用POPUP样式占满屏幕
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, 0);
        SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
        SetWindowPos(hwnd, HWND_TOP, 0, 0, screenWidth, screenHeight, SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
    }
    else {
        // 切换正常模式:使用标准重叠窗口样式
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
        SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
        int x = (screenWidth - W) / 2;
        int y = (screenHeight - H) / 2;
        SetWindowPos(hwnd, HWND_TOP, x, y, W, H, SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 08:51:02