Pyautogui 和 pyscreeze 使用 windll 崩溃。user32.ReleaseDC 失败

Pyautogui and pyscreeze crash with windll.user32.ReleaseDC failed

我正在尝试比较我的 pyautogui 脚本中的某些像素值,但它在多次成功 运行 之后崩溃并显示以下错误消息,或者有时只是在第一次调用时直接崩溃:

Traceback (most recent call last):
  File "F:\Koodit\Python\HeroWars NNet\Assets\autodataGet.py", line 219, in <module>
    battle = observeBattle()
  File "F:\Koodit\Python\HeroWars NNet\Assets\autodataGet.py", line 180, in observeBattle
    statii = getHeroBattlePixels()
  File "F:\Koodit\Python\HeroWars NNet\Assets\autodataGet.py", line 32, in getHeroBattlePixels
    colormatch = pyautogui.pixelMatchesColor(location[0], location[1], alive, tolerance=5)
  File "E:\Program Files\Python\lib\site-packages\pyscreeze\__init__.py", line 557, in pixelMatchesColor
    pix = pixel(x, y)
  File "E:\Program Files\Python\lib\site-packages\pyscreeze\__init__.py", line 582, in pixel
    return (r, g, b)
  File "E:\Program Files\Python\lib\contextlib.py", line 120, in __exit__
    next(self.gen)
  File "E:\Program Files\Python\lib\site-packages\pyscreeze\__init__.py", line 111, in __win32_openDC
    raise WindowsError("windll.user32.ReleaseDC failed : return 0")
OSError: windll.user32.ReleaseDC failed : return 0

我的代码(这被调用了多次,有时它在第一次 运行 时崩溃,有时它 运行 在失败之前调用了大约 100 次,另外,我的屏幕是 4K,所以分辨率变大):

def getSomePixelStatuses():
    someLocations= [
                        [1200, 990],
                        [1300, 990],
                        [1400, 990],
                        [1500, 990],
                        [1602, 990],
                        [1768, 990],
                        [1868, 990],
                        [1968, 990],
                        [2068, 990],
                        [2169, 990]
                        ]
    status = []
    someValue= (92, 13, 12)
    for location in someLocations:
        colormatch = pyautogui.pixelMatchesColor(location[0], location[1], someValue, tolerance=5)
        status.append(colormatch)
    return status

我不知道如何缓解这个问题。 pyautogui 似乎使用 pyscreeze 来读取屏幕上的像素值,而最有可能发生错误的地方是 pyscreeze 像素函数:

def pixel(x, y):
    """
    TODO
    """
    if sys.platform == 'win32':
        # On Windows, calling GetDC() and GetPixel() is twice as fast as using our screenshot() function.
        with __win32_openDC(0) as hdc: # handle will be released automatically
            color = windll.gdi32.GetPixel(hdc, x, y)
            if color < 0:
                raise WindowsError("windll.gdi32.GetPixel failed : return {}".format(color))
            # color is in the format 0xbbggrr https://msdn.microsoft.com/en-us/library/windows/desktop/dd183449(v=vs.85).aspx
            bbggrr = "{:0>6x}".format(color) # bbggrr => 'bbggrr' (hex)
            b, g, r = (int(bbggrr[i:i+2], 16) for i in range(0, 6, 2))
            return (r, g, b)
    else:
        # Need to select only the first three values of the color in
        # case the returned pixel has an alpha channel
        return RGB(*(screenshot().getpixel((x, y))[:3]))

我昨天才安装了这些库,我在 windows 10 上 运行ning python 3.8,pyscreeze 是 0.1.25 版所以理论上一切都应该正常到目前为止,但不知何故最终崩溃了。有没有办法缓解这种情况,要么修改我的代码,甚至修改库本身,要么我的环境不适合这个操作?

嗯,我知道这不是特别有用;但对我来说,这个错误只是通过 运行 我在 3.7 而不是 3.8 上的代码修复的。但是,您不必对代码进行任何更改(除非您使用的是海象!)

在 Windows 上,这可以通过 -3.7 命令行标志完成,只要安装了 3.7

我也有这个错误,我修复了它。只需使用尝试和除外。 虽然是真的: 尝试: x,y = pyautogui.position() 打印(pyautogui.pixel(x,y)) 除了: print("暂时无法获取像素")

鉴于您可能会多次拍摄像素,或者您可以这样做,请尝试并排除奇迹来解决任何 pyscreeze for pyautogui 问题。老实说,我不知道 pyscreeze 是怎么回事,但这对我有用。干杯

我可以像这样在 Python 3.8 上使用 pixel 函数:

try:
    a = pixel(100,100)
> except:
>     a = pixel(100,100)

我不知道为什么会这样,但它确实有效。

这是一个错误。您走在正确的轨道上,因为问题确实出在 pixel() 函数的这一行:

with __win32_openDC(0) as hdc

该函数使用 cyptes.windll,它似乎不能很好地处理有时从 windll.user32.GetDC() 返回的负值,这随后在调用 windll.user32.ReleaseDC() 时创建异常。

pillow 的人员帮助查明了这个问题并提出了解决方案。

  • issue 归档于 pyautogui
  • issue 在 pillow 提交导致解决方案
  • pending PR 在 pyscreeze 上地址

这里是 PyScreeze 和 PyAutoGUI 的维护者。这是 PyScreeze 0.1.28 中已修复的问题,因此您只需更新 运行 pip install -U pyscreeze.

有关更多上下文,这里是报告的 GitHub 问题:https://github.com/asweigart/pyscreeze/pull/73