pygame中的pywin32函数导致程序挂起/“python.exe没有响应”

时间:2015-01-11 07:09:05

标签: python winapi pywin32 win32gui

我有一个程序,它使用pywin32来获取游戏的屏幕截图。使用pygame显示它。我正在经历间歇性的崩溃/悬挂,程序将提供通常的窗口"没有响应"错误,说有时程序运行大约5-10秒后python.exe没有响应。

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

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的新手,我真的不确定是什么原因导致它像那样挂起来。奇怪的是,当程序挂起/没有响应时,放置在程序主循环中的print语句(也称为screengrab())仍会执行。

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

1 个答案:

答案 0 :(得分:1)

我们之前谈过IRC。

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

  

“注意这是阻塞或同步功能,可能不会返回   立即。此函数返回的速度取决于运行时   网络状态,打印服务器配置和   打印机驱动程序实现 - 难以预测的因素   在编写应用程序时。从一个线程调用此函数   管理与用户界面的交互可以使应用程序   似乎没有反应。“

所以这可能是相关的。

在while运行循环的底部添加time.sleep(1)(在导入时间之后)似乎可以防止系统崩溃,所以如果这对你有用并且可以接受一秒钟的延迟,那么这是一个选项。

你真正想做的是能够在后台调用PrintWindow并在PrintWindow返回时更新屏幕,但你可能不得不做一些与文件读/写锁和/或线程有关的愚蠢行为。所以这真的取决于它的用途以及对你来说更重要的事情。