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