【问题标题】:Capturing the screen behind the window捕捉窗口后面的屏幕
【发布时间】:2018-03-12 23:15:43
【问题描述】:

我想编写一个 Windows C++ 应用程序,其中窗口的内容是窗口后面的任何内容(就好像窗口是透明的一样)。也就是说,我想检索我的窗口的边界框;捕获下面的这些坐标,并将它们绘制在我的窗口上。因此,我可以在捕获期间排除窗口本身是至关重要的。

“为什么不让窗口透明呢?”你问。因为对我来说下一步是修改该图像。我想在上面应用一些任意过滤器。例如,假设我想模糊该图像,使我的窗户看起来像一块磨砂玻璃。

我尝试使用 https://code.msdn.microsoft.com/windowsdesktop/Magnification-API-Sample-14269fd2 的放大 API 示例,它实际上为我提供了不包括我的窗口的屏幕内容。但是,重新渲染图像是在计时器中完成的,这会导致图像非常抖动;而且我不知道如何检索该图像并将任意转换应用于该图像。

我不知道从哪里开始,在这一点上真的可以使用一些指针。对不起,如果我从愚蠢的角度来处理这个问题。

编辑:我正在添加我的意思的模型:

编辑 2: 就像在放大 API 示例中一样,视图会不断刷新(尽可能频繁,为了论证的缘故,每 16 毫秒说一次)。示例见Visolve Deflector;尽管它不会对捕获的区域施加任何影响。

再次,我将在之后修改图像数据;因此我无法使用 Magnification API 的内核矩阵支持。

【问题讨论】:

  • blur effect 已经有一个 API。
  • 模糊效果是一个例子,我想对图像应用任意变换。
  • 这似乎不太现实,因为它需要侵入合成管理器的工作(这就是提到的放大 API 似乎执行的操作)。也许隐藏您的窗口并截取后面的任何内容以显示为窗口内容就足够了,或者您需要动态更新它?
  • 在这种情况下是否可以使用放大API检索图像,然后从组件中读取图像数据?
  • 屏幕截图不需要放大 API。只需创建一个位图,然后将BitBlt 从桌面创建到该位图。见example

标签: c++ windows winapi


【解决方案1】:

您没有指定这是一次性活动,还是您需要在窗口后面连续显示内容(例如放大镜/等)。如果连续,您可能需要的更新频率是多少。

无论如何,我看到两个主要用例:

  1. 您的应用程序背后的内容是恒定的您可能不相信,但 大多数情况下,窗口后面的内容不会改变
  2. 窗口后面的内容是变化/动画:这是一个 更棘手的情况。

因此,如果您可以放弃非常量/动画背景用例,则解决方案在单镜头和连续流情况下都非常简单:

  1. 隐藏您的应用程序窗口
  2. 截屏并缓存!
  3. 显示您的应用程序(裁剪除应用程序主窗口边界框之外的所有内容),现在用户可以应用过滤器
  4. 即使用户更改了过滤器,也要将其重新应用到缓存的图像。
  5. 跟踪窗口的WM_MOVE/WM_SIZE 并针对新尺寸重复上述过程。

此外,如果您需要精确,请使用 SetWindowsHookEx 进行 CBT/等。

我头顶的角落案例:

  1. 通知图标/气球工具提示
  2. 桌面后台调度(Windows 第三方应用)
  3. 特定于应用程序的消息框等!

希望这会有所帮助!

【讨论】:

  • 连续,因此任何隐藏/捕获/显示循环都会导致大量闪烁。
  • @kubuzetto 感谢您提供详细信息,如果您的大部分背景是静态或动画的,您能否提供帮助? (因为将您提到的变换连续放在动画背景上可能真的会导致系统崩溃,所以这是一个有效的用例吗?)摆脱我上面的建议(即跟踪WM_MOVEWM_SIZE 的事情,并且仅在窗口位置发生变化时才执行显示/隐藏功能。这将防止闪烁(并提高性能)。
  • 桌面组合管理器持续刷新屏幕(如果需要),我看不出这“真的会导致系统崩溃”我>。这只是猜测,也可能是错误的。无论如何,这并没有解决所提出的问题,只是声称解决方案并非微不足道。这没有帮助。
  • 事先不知道后台的行为。动画内容是很有可能的。
  • @IInspectable 我没有指向窗口刷新,我担心 kukuzetto 将在刷新的图像上持续使用的转换(用他的话来说低至 16 毫秒),如果他的可能需要一些处理捕获窗口大小比较大。
【解决方案2】:

您可以从修改 MAGCOLOREFFECT 开始。在 MagnifierSample.cpp 我们有:

if (ret) 
{ 
    MAGCOLOREFFECT magEffectInvert =  
    {{ // MagEffectInvert 
        { -1.0f,  0.0f,  0.0f,  0.0f,  0.0f }, 
        {  0.0f, -1.0f,  0.0f,  0.0f,  0.0f }, 
        {  0.0f,  0.0f, -1.0f,  0.0f,  0.0f }, 
        {  0.0f,  0.0f,  0.0f,  1.0f,  0.0f }, 
        {  1.0f,  1.0f,  1.0f,  0.0f,  1.0f }  
    }}; 

    ret = MagSetColorEffect(hwndMag,&magEffectInvert); 
} 

Using a Color Matrix to Transform a Single Color.

对于更高级的效果,您可以将内容传送到内存设备上下文。

【讨论】:

  • 我看过那个示例代码,但我想对图像应用任意变换。
  • 我会尝试使用 WM_PRINTCLIENT 获取控制内容。如果要将修改后的图像置于放大控件中,请将其子类化并处理 WM_PAINT。当它不实现 WM_PRINTCLIENT 或在 WM_PAINT 之外绘制时,它可能会更难。
  • 澄清一下,您的建议是无论如何都要使用放大API;然后在每个 WM_PAINT 事件中读取hwndMag 的内容,然后使用数据在第二个控件上呈现;正确的?在这种情况下,我可以将第一个控件隐藏起来吗(我的意思是它还会更新吗)?
  • 使用 Spy++ 检查,WC_MAGNIFIER 控件包含子控件“硬件放大镜”,其中包含静态控件,因此子类化是有问题的。为了让它工作,你实际上会破解它,但不能保证它可以在所有系统上工作。我认为这是一种错误的方式。不知何故,你必须重新创建放大 Api 方式,但我不知道如何。有时它会闪烁并且可以通过它看到下面的窗口,因此它可能会在短时间内从桌面上移除。
【解决方案3】:

我已经使用“GetForeGroundWindow”和“PrintWindow”实现了类似的功能。

这有点牵扯,但这里有一张图片。图像使用其源更新,但速度很慢,因此存在明显滞后(即 0.2 秒 = 0.5 秒) 我没有选择模糊效果,而是选择了 SinWave 效果。此外,使用 GetForeGroundWindow 基本上意味着它只能复制一个窗口的内容。如果您想听到更多信息,请回复,我将整理一些步骤和一个示例 repo。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-04
    相关资源
    最近更新 更多