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); } }
异常原因分析
窗口样式组合错误
切换回正常模式时,手动组合的窗口样式缺少了WS_CAPTION(标题栏核心样式)。标准重叠窗口应使用WS_OVERLAPPEDWINDOW预定义组合样式,它包含WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU等所有必要的窗口框架样式,手动组合时遗漏关键样式会导致非客户区(标题栏、边框)绘制异常。GDI资源泄漏
每次调用GetDC(NULL)获取屏幕DC后,未调用ReleaseDC(NULL, hdc)释放资源,长期运行会导致GDI资源耗尽,虽不是当前显示异常的直接原因,但属于必须修复的问题。样式修改后的同步逻辑缺陷
即使添加了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
相关产品推荐
相关产品推荐

