Nyxeria
Nyxeria

Reputation: 383

Pyautogui and pyscreeze crash with windll.user32.ReleaseDC failed

I'm trying to compare certain pixel values in my pyautogui script, but it crashes with following error message after either multiple successful runs, or sometimes just straight on the first call:

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

My code (this is called multiple times, sometimes it crashes on first run, sometimes it runs nicely for around 100 calls before failing, also, my screen is 4K, so the resolutions get big):

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

I have no idea how to mitigate this problem. It would seem that pyautogui uses pyscreeze to read pixel values on screen, and most probable candidate for the place where error occurs is the pyscreeze pixel function:

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]))

I installed these libraries just yesterday, and I'm running python 3.8 on windows 10, and pyscreeze is version 0.1.25 so in theory everything should be up to date, but somehow something ends up crashing. Is there a way to mitigate this, either modifying my code, or even the library itself, or is my environment not suitable for this operation?

Upvotes: 3

Views: 11458

Answers (5)

Al Sweigart
Al Sweigart

Reputation: 12969

PyScreeze and PyAutoGUI maintainer here. This is an issue that has been fixed in PyScreeze 0.1.28, so you just need to update it by running pip install -U pyscreeze.

For more context, here's the GitHub issue where it was reported: https://github.com/asweigart/pyscreeze/pull/73

Upvotes: 3

Hendy
Hendy

Reputation: 10604

It's a bug. You were on the right track, as the problem is indeed in this line of the pixel() function:

with __win32_openDC(0) as hdc

That function uses cyptes.windll which doesn't seem to do well with the negative values sometimes returned from windll.user32.GetDC(), which subsequently creates an exception when windll.user32.ReleaseDC() is called.

The folks at pillow helped track this down and propose a fix.

  • issue filed at pyautogui
  • issue filed at pillow which led to the solution
  • pending PR at pyscreeze to address

Upvotes: 2

Hugo Salvador
Hugo Salvador

Reputation: 1104

I can use pixel function on Python 3.8 like this:

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

I don't have any clue why this works, but it works.

Upvotes: 0

Troy
Troy

Reputation: 1

I had this error too and i fixed it. Just use try and except. While true: try: x,y = pyautogui.position() print(pyautogui.pixel(x,y)) except: print("Cannot get pixel for the moment")

Given that you might be taking pixels multiple times, or you can do so, try and except works wonders to solve any pyscreeze for pyautogui issue. Honestly i dont know whats up with pyscreeze, but this works for me. Cheers

Upvotes: -1

Starwort
Starwort

Reputation: 83

Well I know it's not particularly helpful; but for me, this error was fixed simply by running my code on 3.7 instead of 3.8. There shouldn't be any changes you have to make to your code, however (unless you were using walrus!)

On Windows, this can be done with the -3.7 command line flag, as long as 3.7 is installed

Upvotes: 7

Related Questions