我正在研究為什么在運行我的 Windows 應用程式時,它在呈現實際應用程式之前(即,在收到 WM_ERASEBKGND 和 WM_PAINT 之前)有一小段白色背景閃爍。
現在,我剛剛注意到這個問題也存在于 Visual Studio 創建的默認示例應用程式中。至少在 Windows 10,21H1(在 VS2008 和 VS2013 中)下運行時我就是這種情況。
在創建“新的 Win32 專案”之后,您唯一需要做的就是更改視窗類的背景顏色,例如,更改為紅色:
//wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW 1);
wcex.hbrBackground = (HBRUSH) CreateSolidBrush(RGB(255, 0, 0));
然后在 WndProc 中添加一個帶有 Sleep 的 WM_ERASEBKGND:
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_ERASEBKGND:
Sleep(1000);
return DefWindowProc(hWnd, message, wParam, lParam);
睡眠夸大了問題,導致白色背景顯示至少一秒鐘。之后,紅色背景按預期繪制。
在運行具有這些更改的應用程式時,我包含了一個簡短的
這意味著 Windows 確實知道并尊重 hbrBackground,這很棒!出于某種奇怪的原因,它只是沒有清除它,而是將其清除為白色。
(順便說一句,我使用“255 255 255”設定檢查了注冊表中的所有系統顏色(HKEY_CURRENT_USER\Control Panel\Colors HKEY_CURRENT_USER\Control Panel\Desktop\Colors)并強行更改它們以查看是否會更改初始白色背景。但沒有運氣。這讓我得出結論,白色背景不是系統顏色。)
無論如何,以上引導我嘗試在 ShowWindow 之后以編程方式調整視窗大小。但是由于我不希望它在打開時閃爍,所以在螢屏外執行 ShowWindow。
所以這里是替換常規 ShowWindow(..) 的代碼:
int x0 = GetSystemMetrics(SM_XVIRTUALSCREEN);
int x1 = GetSystemMetrics(SM_CXVIRTUALSCREEN);
RECT rect;
GetWindowRect(hWnd, &rect);
// resize and move off-screen
SetWindowPos(hWnd, NULL, x1-x0, 0, 0, 0, SWP_NOREDRAW );
// show window
ShowWindow(hWnd,nCmdShow);
// restore and redraw
SetWindowPos(hWnd, NULL, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0 );
現在,我稱之為黑客。然而,它不依賴于 WM_ERASEBKGND 或 WM_PAINT,所以應該不存在時序問題。此外,該視窗的顯示與常規 ShowWindow(...) 完全一樣,只是使用正確的 hbrBackground,這正是我想要的。
這是@ 25Hz 的樣子:

請注意,沒有白色背景的閃光。
請注意,我已經嘗試撰寫代碼來滿足虛擬桌面/多顯示幕的需求,但還沒有實際測驗過。
但不幸的是,一切都不是很好和花花公子。在我寫這個答案的時候,我用 OBSStudio 錄制 @ 60Hz 做了很多試運行,并瀏覽了鏡頭。在那里,我發現一個在打開的視窗框架內僅顯示垃圾(顯然來自 Chrome),僅顯示一幀。這是一個放慢的重播:

我難住了。也許這才是真正的問題?
uj5u.com熱心網友回復:
一個更有爭議的答案可能是這只是 Windows 中的一個錯誤。
作為參考,(除了我已經發布的來自 Windows 10 的現有 GIF)這里是在 Windows XP、Windows 7 和 Windows 11 中使用和不使用后臺擦除運行的示例應用程式的錄音。
視窗 XP:
Windows XP:無 WM_ERASEBKGND/WM_PAINT:OK(無白色背景)

Windows XP:使用 WM_ERASEBKGND:OK(無白色背景)

Windows 7的:
Windows 7:沒有 WM_ERASEBKGND/WM_PAINT:不正常(白色背景)

Windows 7:使用 WM_ERASEBKGND:不正常(白色背景)

Windows 7:使用 WM_ERASEBKGND 睡眠:不正常(白色背景)

禁用 Aero 的 Windows 7:
禁用 Aero 的 Windows 7:無 WM_ERASEBKGND/WM_PAINT:正常(無白色背景)

禁用 Aero 的 Windows 7:使用 WM_ERASEBKGND:OK(無白色背景)

Windows 7 with Aero disabled: With WM_ERASEBKGND Sleep: OK (no white background)

Windows 11 (with Animation disabled):
Windows 11: Without WM_ERASEBKGND/WM_PAINT: NOT OK (white background)

Windows 11: With WM_ERASEBKGND: OK (no white background)

Windows 11: With WM_ERASEBKGND Sleep: NOT OK (white background)

I've added Sleep to tests where it was hard to see the issue.
To sum up:
- Windows XP: No issue. Everything seems to work as expected.
- Windows 7: Issue occurs when Aero is enabled (Windows 7 theme), but not when it is disabled (Classic theme).
- Windows 10: Issue occurs for all tests.
- Windows 11: Issue occurs, but works without Sleep added. Most likely since this was running on a faster machine.
因此,雖然我無法從這些測驗中得出任何可靠的結論,但看起來這種行為確實是在帶有 Aero 的 Windows 7 中引入的。
如果有人可以揭穿這一說法,請在下面發表評論。
uj5u.com熱心網友回復:
我做了一些更多的測驗,并想發布這個問題的潛在答案。現在,這主要基于@JonathanPotter 的建議,因此完全歸功于他。雖然它并沒有真正解決問題,但它確實減輕了很多。
現在,理想情況下,如果 Windows 能夠簡單地使用正確的初始背景顏色渲染視窗,那就太好了,但是無論我多么努力地嘗試,我都只能通過使用 WM_ERASEBKGND 或 WM_PAINT 來更新背景顏色。
因此,顯示視窗(即使用 ShowWindow)和實際清除背景(WM_ERASEBKGND)之間的時間延遲似乎是問題的關鍵。因此,對其進行概要分析是有意義的。我通過記錄呼叫 ShowWindow 和使用 QueryPerformanceCounter 到達 WM_ERASEBKGND 之間的時間差來做到這一點。
因此,在運行 Window 10 的 i7-4960HQ CPU @ 2.60GHz 上,ShowWindow 和 WM_ERASEBKGND 之間的時間在100 - 317ms之間。它波動很大。這是一個普通的 Win32 示例應用程式,內置 Release 沒有任何 Sleeps 或類似的東西,但使用紅色 hbrBackground 來顯示問題。這意味著在繪制紅色背景之前,白色背景在幾幀內清晰可見。這是@ 25Hz 捕獲的影片 gif:
該影片中的 3 幀可見白色背景。
現在潛在的解決方法是在顯示視窗之前使用 SetWindowPos 和 RedrawWindow 的組合。
對于我的測驗,我只是在呼叫 ShowWindow(..) 之前添加了這兩行:
SetWindowPos(hWnd, NULL, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE);
盡管 RedrawWindow 似乎沒有任何區別。再次分析,ShowWindow 和 WM_ERASEBKGND 之間的時間現在是10 - 23ms。10 倍加速!
再次,捕獲的影片 gif(使用 SetWindowPos)@ 25Hz:
這清楚地表明白色背景的閃光消失了,因此問題已解決。這就像白天和黑夜。
Now, I would argue that this is not a fix, but rather a workaround. Since the underlying problem of Windows using a white background color is still there. And since this is a timing issue, I can easily imagine that the white background could show up again, say if the system was sluggish or busy doing other stuff. Similarly, having a faster system means you that you are less likely to see this in the first place, effectively hiding the issue. But simply setting a breakpoint in WM_ERASEBKGND will still show you a white window.
Also, I have no explanation for the speed-up. I tracked the number of messages in the message pump, and they are the same in both scenarios.
Now, I'm still hoping for a better fix. I find it hard to believe that the Microsoft engineers found it cool to fill all freshly created Windows with a hardcoded 0xFFFFFF, so I'm hoping that this color is actually read from somewhere, and thus possible to change, so the initial background matches the hbrBackground.
Please feel free to post alternative answers, questions, or suggestions. I will of course update this thread if I figure out anything else.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/345297.html
標籤:登录
