在Vista系统中确定窗口可见性

4

我希望确定某个窗口对用户是否可见或隐藏/被遮挡。在Windows XP中,我将使用GetClipBox()函数并检查NULLREGION或空RECT返回值。这非常有效,但在Windows Vista上,如果另一个窗口遮挡了该窗口,则不起作用。在这种情况下,GetClipBox()会返回具有非空RECT的SIMPLEREGION。

请问有人知道为什么在Vista上不起作用,或者是否有其他方法来检查窗口是否可见于用户?

5个回答

3
简单地说,在DWM启用时,GetClipBox()未返回NULLREGION的简单原因是您没有被裁剪! DWM的整个重点在于每个窗口(不是子窗口,如按钮或编辑框)都有自己的缓冲区可供绘制,因此前景窗口可以移动而无需填充它们后面的窗口。
举个简单的例子,将鼠标悬停在任务栏中处于后台的窗口条目上,观察预览中更新的内容。
还要注意的是,在玻璃边缘下,您的窗口可能会被其他窗口完全覆盖,但仍然可见! (你甚至无法测试客户端区域,因为像Windows Media Player这样使用的扩展玻璃边缘 - 将其调整为最小并查看它使用整个区域的玻璃!)当然,分层窗口(从XP开始)和自定义窗口区域意味着这一直是可能的,但现在它是默认值。
总结/TL;DR:
如果您正在进行大量动画/花哨效果,并希望在DWM下运行时减少CPU使用率,则最好的方法可能是检测应用程序何时失去焦点并回退到更友好的CPU更新(不是不更新!如果您收到WM_PAINT消息并忽略它,因为您在后台,则在激活时不会收到该消息!)。

感谢您的详细解释!正如您所猜测的那样,我的应用正在执行CPU密集型动画,因此我尝试在窗口不可见时减少CPU使用率。检查我的应用是否为前台窗口听起来像是一个合理的解决方法,我会尝试一下。 - flashk

2

您的Vista安装中,桌面窗口管理器合成是否打开?我猜测它是打开的,如果您关闭它,您将得到预期的XP行为。问题在于,在启用DWM合成的Vista下,窗口处理方式已经发生了很大变化,我认为没有简单的方法可以得到您想要的结果。


2
在您安装的Vista中,桌面窗口管理器组合是否已打开?我猜它是打开的,如果将其关闭,您将获得预期的XP行为。问题在于,在启用DWM组合的Vista下,处理窗口的方式发生了很大变化,我不认为会有一种简单的方法来实现您想要的效果。
是的,DWM在我的计算机上已启用。我尝试了以下步骤来测试您的假设:
1.右键单击我的应用程序,选择“属性”。 2.单击“兼容性”选项卡。 3.启用“禁用桌面组合”复选框。 4.单击“应用”。
之后,GetClipBox()函数可以正常工作。所以您的直觉是正确的。我发现我可以通过在我的应用程序中使用以下功能来进行编程:
DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);

然而,这会在我的应用程序运行时禁用透明效果,这是不可取的。我更喜欢一个不那么显眼的解决方案。无论如何,感谢您的建议!

1
一种有些混乱的方法是获取您想要检查的窗口的位置/大小,然后循环遍历在Z顺序中高于它的所有窗口,并计算它们覆盖您窗口的哪些部分。

0

既然您已经知道了在XP和Vista上(启用或禁用DWM)GetClipRect的输出,那么您可以创建一个函数来确定这个值,它会根据不同的操作系统选择不同的执行路径。伪代码如下:

function bool IsWindowVisible()
{
   bool isVisible = false;

   if (OSVersion == "XP")
   {
      // GetClipRect tests which run on XP and set isVisible
   }
   else if (OSVersion == "Vista")
   {
      if (DWMCompisitionEnabled == true)
      {
         // GetClipRect tests for Vista with DWM enabled and set isVisible
      }
      else
      {
         // GetClipRect tests for Vista with DWM disabled and set isVisible
      }
   }
   return isVisible;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接