WinAPI双缓冲实现异常,屏幕频繁闪烁问题排查求助
WinAPI双缓冲闪烁问题排查与修复
问题描述
我正在学习WinAPI双缓冲技术,运行下方代码后屏幕出现严重闪烁现象。我认为自己的实现逻辑无误,但不知问题出在哪里?
绘制逻辑为:将memdc1与memdc2绘制到memdc,再将memdc绘制到hdc。
原代码
switch (iMsg) { case WM_CREATE: hdc = GetDC(hwnd); GetClientRect(hwnd, &clientRt); PlaceCenterScreen(hwnd); SetTimer(hwnd, 1, 10, NULL); hMixBit = CreateCompatibleBitmap(hdc, 819, 614); hHouseBit = (HBITMAP)LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_HOUSE)); hTigerBit = (HBITMAP)LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_TIGER)); ReleaseDC(hwnd, hdc); break; case WM_TIMER: posX += 3; InvalidateRgn(hwnd, NULL, true); break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); memdc = CreateCompatibleDC(hdc); memdc1 = CreateCompatibleDC(memdc); memdc2 = CreateCompatibleDC(memdc); oldHouseBit = (HBITMAP)SelectObject(memdc1, hHouseBit); oldTigerBit = (HBITMAP)SelectObject(memdc2, hTigerBit); oldMixBit = (HBITMAP)SelectObject(memdc, hMixBit); BitBlt(memdc, 0, 0, 819, 614, memdc1, 0, 0, SRCCOPY); BitBlt(memdc, posX, 0, 67, 47, memdc2, 0, 0, SRCCOPY); BitBlt(hdc, 0, 0, 819, 614, memdc, 0, 0, SRCCOPY); SelectObject(memdc1, oldHouseBit); SelectObject(memdc2, oldTigerBit); SelectObject(memdc, oldMixBit);
问题分析与修复方案
1. 系统自动擦除背景导致闪烁
InvalidateRgn(hwnd, NULL, true)的第三个参数设为true时,系统会在重绘前自动擦除窗口背景,擦除动作和后续双缓冲绘制的间隔会直接造成视觉闪烁。将参数改为false,让双缓冲统一绘制完整画面,避免系统自动擦除:
InvalidateRgn(hwnd, NULL, false);
2. 未销毁临时DC引发资源泄漏
WM_PAINT中创建的memdc、memdc1、memdc2没有调用DeleteDC销毁,会持续消耗GDI资源,长时间运行后资源不足会引发绘制异常和闪烁。恢复GDI对象后必须销毁这些临时DC:
SelectObject(memdc1, oldHouseBit); SelectObject(memdc2, oldTigerBit); SelectObject(memdc, oldMixBit); // 新增:销毁临时DC DeleteDC(memdc2); DeleteDC(memdc1); DeleteDC(memdc);
3. 缺少EndPaint导致重复重绘
WM_PAINT消息中调用BeginPaint后必须调用EndPaint,否则系统会认为窗口仍需重绘,不断发送WM_PAINT消息,导致重复绘制和闪烁。在绘制完成后添加:
EndPaint(hwnd, &ps);
4. 可选优化:提前创建静态DC
每次WM_PAINT都创建memdc1、memdc2会增加资源开销和绘制延迟,可将这两个DC的创建移到WM_CREATE中只初始化一次:
case WM_CREATE: hdc = GetDC(hwnd); GetClientRect(hwnd, &clientRt); PlaceCenterScreen(hwnd); SetTimer(hwnd, 1, 10, NULL); hMixBit = CreateCompatibleBitmap(hdc, 819, 614); hHouseBit = (HBITMAP)LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_HOUSE)); hTigerBit = (HBITMAP)LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_TIGER)); // 提前创建静态DC并绑定位图 memdc1 = CreateCompatibleDC(hdc); memdc2 = CreateCompatibleDC(hdc); SelectObject(memdc1, hHouseBit); SelectObject(memdc2, hTigerBit); ReleaseDC(hwnd, hdc); break;
同时在WM_DESTROY中销毁这些静态DC,避免资源泄漏。
修正后的WM_PAINT代码示例
case WM_PAINT: hdc = BeginPaint(hwnd, &ps); memdc = CreateCompatibleDC(hdc); oldMixBit = (HBITMAP)SelectObject(memdc, hMixBit); // 使用提前创建好的memdc1、memdc2 BitBlt(memdc, 0, 0, 819, 614, memdc1, 0, 0, SRCCOPY); BitBlt(memdc, posX, 0, 67, 47, memdc2, 0, 0, SRCCOPY); BitBlt(hdc, 0, 0, 819, 614, memdc, 0, 0, SRCCOPY); SelectObject(memdc, oldMixBit); DeleteDC(memdc); EndPaint(hwnd, &ps); break;
内容的提问来源于stack exchange,提问作者Cho
相关产品推荐
相关产品推荐

