如何在不重复工作的情况下使用 pywin32 获取 window 矩形和设备上下文?

How can pywin32 be used to get the window rectangle and device context without duplicating work?

我正在尝试了解 win32 api / pywin32 包,并且我有截取具有特定名称的 window 屏幕截图的代码。我很难理解 win32 api,并且当前代码在两个不同的时间有效地搜索相同的 window。我假设有可能做得更好。这是代码:

1 - 预赛:

from PIL import Image
import win32ui, win32gui, win32con

#name of window to screenshot
name = "Photos"

2- 我第一次找到 window,我能够使用结果来获取有关其形状和位置的信息:

window = win32ui.FindWindow(None, name)
left, top, right, bottom = window.GetWindowRect()
width = right - left
height = bottom - top

3 - 我第二次找到 window,我能够将结果输入 GetWindowDC 函数。我的代码的其余部分(未显示)使用此设备上下文信息来执行屏幕截图。

def findit(hwnd,ctx):
    if win32gui.GetWindowText(hwnd) == name: # check the title
        return hwnd
window = win32gui.EnumWindows(findit,None)

#convert this into a device context handle
windowDC = win32gui.GetWindowDC(window)

我想知道是否有一种方法可以重现 left, top, right, bottomwindowDC 而无需使用两种不同的方法来找到我想要的 window。此外,我想直观地了解 window 中包含的数据是第一次计算还是第二次计算。我对这种理解比实际截屏更感兴趣,所以以完全不同的方式完成这项工作的代码可能不会有帮助。

请使用win32gui.FindWindow(None, name).

最小代码:

import win32gui
import win32ui
import win32con

name = "test.txt - Notepad"
hwnd = win32gui.FindWindow(None, name)
left, top, right, bot = win32gui.GetWindowRect(hwnd)
w = right - left
h = bot - top
print(w,h)
wDC = win32gui.GetWindowDC(hwnd)
dcObj=win32ui.CreateDCFromHandle(wDC)
cDC=dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, w, h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0,0),(w, h) , dcObj, (0,0), win32con.SRCCOPY)
dataBitMap.SaveBitmapFile(cDC, "1.bmp")
# Free Resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())

我的猜测是 winapi 同名 return 不同库中的不同类型。

例如win32gui.FindWindowwin32ui.FindWindow

在对特定应用程序进行截图时,您会遇到一些其他问题,例如无法正确对Firefox进行截图。

还有另一种方法可以解决这个问题,参考:

作为补充:

我用C++测试了EnumWindowsFindWindow,它们会return相同的数据,使用GetWindowDC不会出错。

这是 C++ 代码:

#include <Windows.h>
#include <string>
#include <iostream>


static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM m) {
    RECT rc;
    int length = GetWindowTextLength(hWnd);
    char* buffer = new char[length + 1];
    GetWindowText(hWnd, buffer, length + 1);
    if (!strcmp(buffer, "Photos"))
    {       
        HDC hdc = GetWindowDC(hWnd);
        GetWindowRect(hWnd, &rc);
        std::cout <<"EnumWindows: "<< rc.right-rc.left <<" "<< rc.bottom-rc.top<<std::endl;
        std::cout <<"EnumWindows: "<< hWnd << std::endl;
    }
    return TRUE;
}

int main()
{
    RECT rc;
    HWND window = FindWindow(NULL, "Photos");
    GetWindowRect(window, &rc);
    std::cout <<"FindWindow: "<< rc.right - rc.left <<" "<< rc.bottom - rc.top << std::endl;
    std::cout <<"FindWindow: "<< window << std::endl;

    HDC hdc = GetWindowDC(window);

    EnumWindows(enumWindowCallback, NULL);
    return 0;
}

调试:

FindWindow: 649 640
FindWindow: 00080A6A
EnumWindows: 649 640
EnumWindows: 00080A6A