我是来找你帮忙解决最近我的计划遇到的一个问题.
当我尝试使用BitBlt和CreateCompatibleBitmap:win32ui.error: BitBlt failed & CreateCompatibleBitmap时,我会收到这个错误,值得一提的是,只有当我的程序从不同的线程调用这些函数时才会发生这种情况,可能是同时发生的。
也许win32gui的方法不是多线程兼容的?
我目前正在将调用包装在try-except块中,以防止程序崩溃,但显然线程正在竞争使用BitBlt y CreateCompatibleBitmap方法。
我想忽略错误消息,让线程竞争这场比赛,但这真的让我害怕,这可能导致一个糟糕的程序变得缓慢或破坏一些东西,避免数百万这样的错误。
我每隔50到100毫秒不断地给BitBlt和CreateCompatibleBitmap打电话。
这里是我从多个线程调用的函数的一个例子:
当我这样做的时候,我得到了win32gui.error CreateCompatibleBitmap failed
def get_capture_icons():
hwndDC_icons = win32gui.GetWindowDC(game_client_hwnd)
mfcDC_icons = win32ui.CreateDCFromHandle(hwndDC_icons)
saveDC_icons = mfcDC_icons.CreateCompatibleDC()
saveBitMap_icons = win32ui.CreateBitmap()
saveBitMap_icons.CreateCompatibleBitmap(mfcDC_icons, 106, 11)
saveDC_icons.SelectObject(saveBitMap_icons)
saveDC_icons.BitBlt((-16, -39), (1366, 768), mfcDC_icons, (1191, 256), win32con.SRCCOPY)
img = Image.frombuffer('RGB', (106, 11), saveBitMap_icons.GetBitmapBits(True), 'raw', 'BGRX', 0, 1)
mfcDC_icons.DeleteDC()
saveDC_icons.DeleteDC()
win32gui.ReleaseDC(game_client_hwnd, hwndDC_icons)
win32gui.DeleteObject(saveBitMap_icons.GetHandle())
return img但是,当我将对象保存在全局变量中时,就会得到win32gui.error BitBlt failed
def load_capturer_icons():
global hwndDC_icons, mfcDC_icons, saveDC_icons, saveBitMap_icons
hwndDC_icons = win32gui.GetWindowDC(game_client_hwnd)
mfcDC_icons = win32ui.CreateDCFromHandle(hwndDC_icons)
saveDC_icons = mfcDC_icons.CreateCompatibleDC()
saveBitMap_icons = win32ui.CreateBitmap()
saveBitMap_icons.CreateCompatibleBitmap(mfcDC_icons, 106, 11)
saveDC_icons.SelectObject(saveBitMap_icons)
def get_capture_icons():
saveDC_icons.BitBlt((-16, -39), (1366, 768), mfcDC_icons, (1191, 256), win32con.SRCCOPY)
return Image.frombuffer('RGB', (106, 11), saveBitMap_icons.GetBitmapBits(True), 'raw', 'BGRX', 0, 1)额外信息:我有2个线程处理scripts
scripting.Thread(target=scripting.Thread.check_queue_scripts, name="Ekko").start()
scripting.Thread(target=scripting.Thread.check_queue_scripts, name="Zoe").start()调用get_capture_icons并生成本页开头解释的错误的两个脚本的示例
def callback(player, sleep):
get_capture_icons()#call example
script = Script("callback-1", 100)
script.add_callback(callback)
script.register(__name__)
script = Script("callback-2", 100)
script.add_callback(callback)
script.register(__name__)如果我删除其中一个脚本,只保留一个脚本,那么错误将不再出现。
发布于 2022-04-01 00:18:11
多亏了@Tim Roberts,我能够更多地定位自己,我开始了这方面的调查,尽管他的回答不准确,但他非常清楚地知道,同时访问GDI对象会产生争用条件,所以解决方案是使用threading.Lock。
所以现在每个线程都用锁执行脚本。
lock.acquire()
script.execute()
lock.release()from threading import Lock
class Thread(threading.Thread):
def __init__(self, target: 'Callable', name: str = "", lock: threading.Lock = None):
threading.Thread.__init__(self, target=target, args=(self, lock))
self.running = True
self.name = name
def check_queue_scripts(self, lock):
while self.running:
script_name = Scripts.queue.get()
script = Scripts.get_script(script_name)
if script:
if script.to_reload:
Scripts.queue.task_done()
Scripts.reload_script(script)
continue
lock.acquire()
script.execute()
lock.release()
Scripts.queue.task_done()
Scripts.queue.put(script_name)
sleep(1/20)
scripts_lock = Lock()
scripting.Thread(target=scripting.Thread.check_queue_scripts, name="Ekko", lock=scripts_lock).start()
scripting.Thread(target=scripting.Thread.check_queue_scripts, name="Zoe", lock=scripts_lock).start()https://stackoverflow.com/questions/71698973
复制相似问题