pygame 中的 pywin32 函数导致程序挂起/"python.exe is not responding"

pywin32 function in pygame causing program to hang / "python.exe is not responding"

我有一个程序使用 pywin32 截取游戏的屏幕截图并使用 pygame 显示它。我遇到间歇性 crashing/hanging 程序会给出通常的 windows "not responding" 错误,说 python.exe 在程序大约 5-10 秒后没有响应 运行 有时候。

我已将其缩小为以下功能:

def screengrab(self):
    hwnd = self.aoe_hwnd
    left, top, right, bot = win32gui.GetClientRect(hwnd)
    w = right - left
    h = bot - top
    #returns the device context (DC) for the entire window, including title bar, menus, and scroll bars.
    hwndDC = win32gui.GetWindowDC(hwnd)
    #Creates a DC object from an integer handle.
    mfcDC  = win32ui.CreateDCFromHandle(hwndDC)
    #Creates a memory device context (DC) compatible with the specified device.
    saveDC = mfcDC.CreateCompatibleDC()
    saveDC.SetWindowOrg((w - self.map_w,h - self.map_h))
    #Creates bitmap Object
    saveBitMap = win32ui.CreateBitmap()
    #Creates a bitmap object from a HBITMAP.
    saveBitMap.CreateCompatibleBitmap(mfcDC, self.map_w, self.map_h)

    saveDC.SelectObject(saveBitMap)

    # Change the line below depending on whether you want the whole window
    # or just the client area. 
    #result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 1)
    result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 1)
    bmpinfo = saveBitMap.GetInfo()
    bmpstr = saveBitMap.GetBitmapBits(True)
    im = Image.frombuffer(
        'RGB',
        (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
        bmpstr, 'raw', 'BGRX', 0, 1)

    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, hwndDC)

    if result == 1:
        tmp = cStringIO.StringIO()
        im = im.resize(self.window_size)
        im.save(tmp, "bmp")
        tmp.seek(0)
        return tmp

我是 win32 api 的新手,我真的不完全确定是什么导致它那样挂起。奇怪的是,放置在程序主循环中的打印语句(也调用了 screengrab()),在程序 hung/not 响应时仍会执行。

要点上的整个程序:https://gist.github.com/Andygmb/f8ae761e689788136fc0

我们早些时候在 IRC 上讨论过。

我认为您的问题与 windll 的使用有关。user32.PrintWindow。查看 Microsoft documentation for this function,这一行引起了我的注意:

"Note This is a blocking or synchronous function and might not return immediately. How quickly this function returns depends on run-time factors such as network status, print server configuration, and printer driver implementation—factors that are difficult to predict when writing an application. Calling this function from a thread that manages interaction with the user interface could make the application appear to be unresponsive."

所以这可能是相关的。

在 while 运行 循环的底部添加 time.sleep(1)(在导入时间之后)似乎可以防止我的系统崩溃,所以如果这对你和一个人有效第二次延迟是可以接受的,这是一种选择。

您真正想要做的是能够在后台调用 PrintWindow 并在 PrintWindow returns 时更新屏幕,但您可能不得不用文件 read/write 锁 and/or穿线。所以这真的取决于这是为了什么以及什么对你更重要。