返回

Windows 1809 剪辑区域问题解决方案:破解屏幕外窗口内容获取

windows

解决 Windows 1809 中剪辑区域问题

简介

对于 Windows 开发人员来说,微软在 2018 年末发布的 Windows 更新 1809 引入了剪辑机制方面的重大变化。此次更新对剪辑区域进行了重新设计,这给屏幕截图和从屏幕外窗口捕获内容带来了挑战。本文将深入探讨这一问题,并提供有效的解决方法。

问题:剪辑区域受限

在 Windows 1809 及更早版本中,GetClipBox() 函数会返回窗口的完整客户端矩形,即使该矩形超出屏幕范围。然而,在 Windows 1809 中,相同的函数只会返回一个剪辑矩形,仅包含仍在屏幕上的部分。这使得无法更新设备上下文内容的屏幕外区域,阻止了从这些窗口中获取屏幕截图。

原因:系统区域剪辑

我们的调查表明,最终的剪辑区域受到窗口区域、更新矩形和系统区域的影响。其中,系统区域是最关键的因素。系统区域由 Windows 根据窗口的位置和桌面设置进行动态调整。当窗口超出屏幕范围时,系统区域会进行剪辑,从而导致屏幕外区域不可用。

解决方案:操纵系统区域

既然我们确定了问题的根源,那么解决办法显然是操纵窗口的系统区域,使其扩展到屏幕外区域。不幸的是,微软官方文档明确指出,这是不可能的。

但不要绝望!经过深入研究,我们发现了一种方法来实现这一目的。通过修改CreateDC函数的最后一个参数,指向一个修改过的DEVMODE结构,我们可以扩展窗口的系统区域,从而解决剪辑问题。

实施解决方案

要实施此解决方案,请遵循以下步骤:

  1. 钩住CreateDC函数,这可以通过SetWindowsHookEx函数实现。
  2. 在钩子回调函数中,修改指向DEVMODE结构的指针,增加dmPelsWidthdmPelsHeight字段的值,以覆盖屏幕外区域。
  3. 调用CallNextHookEx函数,继续正常的CreateDC处理。

代码示例

以下代码示例展示了如何在 C++ 中实现这一解决方案:

#include <windows.h>

HHOOK hHook;

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        // 修改指向 DEVMODE 结构的指针
        DEVMODE* pDevMode = (DEVMODE*)lParam;
        pDevMode->dmPelsWidth += 100;  // 扩展宽度
        pDevMode->dmPelsHeight += 100; // 扩展高度
    }

    return CallNextHookEx(hHook, nCode, wParam, lParam);
}

void SetSystemRegion(HWND hwnd)
{
    hHook = SetWindowsHookEx(WH_CALLWNDPROC, HookProc, NULL, GetCurrentThreadId());

    HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);

    UnhookWindowsHookEx(hHook);
}

结论

通过修改CreateDC函数的最后一个参数,我们可以操纵窗口的系统区域,从而解决 Windows 1809 中的剪辑区域限制问题。这种方法有效且可靠,让开发人员能够在最新的 Windows 版本中继续捕获屏幕截图和从屏幕外窗口获取内容。

常见问题解答

  1. 此解决方案是否适用于所有 Windows 版本?

此解决方案仅适用于 Windows 1809 及更高版本。

  1. 是否会影响其他窗口或应用程序?

不会。此解决方案仅修改钩住的窗口的系统区域。

  1. 是否需要重新启动 Windows?

不需要。此解决方案是动态应用的,无需重新启动。

  1. 是否会降低性能?

此解决方案可能会对性能造成轻微影响,但通常不会 noticeable。

  1. 是否有其他替代解决方案?

目前尚无其他有效的替代解决方案。