0

I think I've got two threads trying to access this class at the same time.

This is the full function, I use it to grab frames from an application window.

class WindowCapture:
    
    # properties
    w = 0
    h = 0
    hwnd = None
    cropped_x = 0
    cropped_y = 0
    offset_x = 0
    offset_y = 0
    
    # constructor
    def __init__(self, window_name=None):
        # find the handle for the window we want to capture.
        # if no window name is given, capture the entire screen
        if window_name is None:
            self.hwnd = win32gui.GetDesktopWindow()
        else:
            self.hwnd = win32gui.FindWindow(None, window_name)
            if not self.hwnd:
                raise Exception('Window not found: {}'.format(window_name))
    
        # get the window size
        window_rect = win32gui.GetWindowRect(self.hwnd)
        self.w = window_rect[2] - window_rect[0]
        self.h = window_rect[3] - window_rect[1]
    
        # account for the window border and titlebar and cut them off
        border_pixels = 0
        titlebar_pixels = 0
        self.w = self.w - (border_pixels * 2)
        self.h = self.h - titlebar_pixels - border_pixels
        self.cropped_x = border_pixels
        self.cropped_y = titlebar_pixels
    
        # set the cropped coordinates offset so we can translate screenshot
        # images into actual screen positions
        self.offset_x = window_rect[0] + self.cropped_x
        self.offset_y = window_rect[1] + self.cropped_y 
    
    def get_haystack(self):
        # get the window image data
        wDC = win32gui.GetWindowDC(self.hwnd)
        dcObj = win32ui.CreateDCFromHandle(wDC)
        cDC = dcObj.CreateCompatibleDC()
        dataBitMap = win32ui.CreateBitmap()
        dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
        cDC.SelectObject(dataBitMap)
        cDC.BitBlt((0, 0), (self.w, self.h), dcObj, (self.cropped_x, self.cropped_y), win32con.SRCCOPY) 

        # convert the raw data into a format opencv can read
        # dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
        signedIntsArray = dataBitMap.GetBitmapBits(True)
        img = np.fromstring(signedIntsArray, dtype='uint8')
        img.shape = (self.h, self.w, 4)

        # free resources
        dcObj.DeleteDC()
        cDC.DeleteDC()
        win32gui.ReleaseDC(self.hwnd, wDC)
        win32gui.DeleteObject(dataBitMap.GetHandle())
        img = img[...,:3]
        img = np.ascontiguousarray(img)

        return img

The full error:

C:/Users/AppData/Local/Programs/Python/Python39/python.exe "c:/Users/Combined_180222_desktop_version .py"
Exception in thread pvp:
Traceback (most recent call last):
  File "C:\Users\AppData\Local\Programs\Python\Python39\lib\threading.py", line 973, in _bootstrap_inner
    self.run()
  File "C:\Users\AppData\Local\Programs\Python\Python39\lib\threading.py", line 910, in run
    self._target(*self._args, **self._kwargs)
  File "c:\Users\Combined_180222_desktop_version .py", line 98, in pvp_check
    haystack = app_window.get_haystack()
  File "c:\Users\windowcapture.py", line 54, in get_haystack
    cDC.BitBlt((0, 0), (self.w, self.h), dcObj, (self.cropped_x, self.cropped_y), win32con.SRCCOPY)
win32ui.error: BitBlt failed

And the two functions trying to use it:

# initialize the WindowCapture class
# left blank to capture the whole screen
app_window = WindowCapture()

def a():    
    level = r'C:\arrow.jpg'
    level_icon = Vision(level)

    while True:
        haystack = app_window.get_haystack()
        img = level_icon.find(haystack, 0.92, 'points1','levelup')

def b():
    pvp = r'C:\pvp.jpg'
    pvp_icon = Vision(pvp)

    while True:
        haystack = app_window.get_haystack()
        img = pvp_icon.find(haystack, 0.85, 'points1', 'PvP')

And how I'm starting the threads:

t1 = Thread(name='a', target=a)
t2 = Thread(name='b', target=b)

t1.start()
t2.start()

I've got numerous other threads running but they don't access anything other than local information to their functions and aren't causing issues.

These two threads are both trying to access my WindowCapture class and the error appeared after I added the second thread above so I'm presuming that's where the issue is but I'm not certain.

This post talks about race conditions and script locks but I can't seem to find anything to help me understand what's going on and how to fix it.

How do I access a class from multiple threads without them colliding (assuming that's the issue)?

quamrana
  • 33,740
  • 12
  • 54
  • 68
mak47
  • 246
  • 10

0 Answers0