如何以原子方式更新 HWND 的样式和位置?

How can I update an HWND's style and position atomically?

本文关键字:样式 位置 HWND 更新 方式      更新时间:2023-10-16

我正在编写一个Win7桌面应用程序,并希望让它从窗口全屏无缝过渡到窗口全屏(反之亦然(,并且主要通过调用SetWindowLongPtr来更新其样式,然后MoveWindow更新其大小和位置。 问题是窗口闪烁一帧以显示其样式已更新,但未显示新大小和位置。 下一帧一切看起来都正确,但我试图避免这种单帧伪影。

我尝试反转调用 API 的顺序,但它只是改变了工件的外观。 我还尝试隐藏窗口,调用 API,然后显示窗口,但这只会导致窗口消失一帧。

我知道一种选择是创建一个具有所需属性的新窗口,然后销毁旧窗口,但我想找到一个更便宜的替代方案。

那么有没有办法调用这些 API 并让它们以原子方式直观地反映呢? 作为奖励,将多个生成的WM_SIZE消息合并到一个事件中会很好,但我可以在消息处理程序中自己管理它。

在Windows中可靠地执行此类操作是很困难的,特别是因为Vista作为DWM会使事情复杂化。这通常是一个反复试验的问题,直到找到适合您的解决方案。

SetWindowPos有一个 SWP_NOREDRAW 标志,可防止在响应调用时重新绘制窗口。因此,您可以先尝试更改位置,然后更新样式,最后第三次调用以在新位置重绘窗口。例如

SetWindowPos(hWnd, 0, x, y, w, h, SWP_NOREDRAW | SWP_NOZORDER);
SetWindowLongPtr(hWnd, GWL_STYLE, dwNewStyles);
RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE | RDW_FRAME);

MSDN 说:

某些窗口数据被缓存,因此您使用 SetWindowLongPtr 不会生效,直到您调用 SetWindowPos 功能。

所以这应该有效。 也许尝试使用SetWindowPos而不是MoveWindow。

当您收到由这些调用引起的事件时,您是否在窗口进程中做了什么有趣的事情? 特别是,您是否在"修复"尺寸或类似的东西?

签出WM_SETREDRAW ; 使用它来禁用重绘,更改窗口样式,然后调用RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN)以原子方式显示它们。

"窗口全屏"是什么意思? 它和最大化一样吗?

如果是这样,ShowWindow (hwnd, SW_MAXIMIZE)