首页 > 解决方案 > CreateCompatibleDC() 或 DeleteDC() 在 Python 的 continue 循环中失败 - 可能存在内存泄漏?

问题描述

我在下面这个特定的窗口屏幕捕获例程中循环输入一个 opencv 窗口。

问题:在循环中数百次循环后,它突然在代码中标记的两个 FAIL POINTS 中的任何一个处失败。

我怀疑可能存在内存泄漏,但如果我没记错的话,我会删除并释放所需的内容,并在删除对象之前(重新)选择对象

(我使用此方法的原因是,即使特定窗口处于非活动状态且在后台,并且我没有发现任何其他模块/方法实际有效,对我而言能够捕获特定窗口也很重要。)

我在看什么?

import win32gui
import win32ui
from PIL import Image
import numpy as np
import cv2

while True:

        target_window = win32gui.FindWindow(None, ("Analytics dashboard - Google Chrome"))       
        
        hwndDC = win32gui.GetWindowDC(target_window) 
        mfcDC  = win32ui.CreateDCFromHandle(hwndDC)  

        saveDC = mfcDC.CreateCompatibleDC()  #### <-- RANDOM FAIL POINT 1: win32ui.error: CreateCompatibleDC failed
                
        saveBitMap = win32ui.CreateBitmap()
        saveBitMap.CreateCompatibleBitmap(mfcDC, screen_width, screen_height)
        saveDC.SelectObject(saveBitMap)    
        result = windll.user32.PrintWindow(target_window, saveDC.GetSafeHdc(), 3)
        bmpinfo = saveBitMap.GetInfo()
        bmpstr = saveBitMap.GetBitmapBits(True)
        
        screen_image = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)        

        mfcDC.DeleteDC()  #### <-- RANDOM FAIL POINT 2: win32ui.error: DeleteDC failed

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

        image = cv2.cvtColor(np.array(screen_image), cv2.IMREAD_ANYCOLOR)

标签: pythonmemory-leakspywin32win32guiwin32-process

解决方案


我尝试了上面的代码,ctypes.windll.user32.PrintWindow没有 GDI 泄漏。PrintWindow的第三个参数应该是PW_CLIENTONLY(1),或者有未记录的PW_RENDERFULLCONTENT(2) 选项。未记录的代码不可靠。我不知道常数 (3) 指的是什么。

如果 Chrome 是顶部窗口,您应该只截取桌面的屏幕截图。这将是合规的。

如果您删除循环外的一些代码可能会有所帮助,至少它会更有效。

import ctypes
import win32gui 
import win32ui
import win32con
from PIL import Image

hdesktop = win32gui.GetDesktopWindow()
(l, r, width, height) = win32gui.GetClientRect(hdesktop)
hdc = win32gui.GetWindowDC(hdesktop)
dc  = win32ui.CreateDCFromHandle(hdc)
memdc = dc.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(dc, width, height)
memdc.SelectObject(bitmap)

while True:
    hwnd = win32gui.FindWindow("Chrome_WidgetWin_1", None)
    if hwnd == 0:
        break
    result = ctypes.windll.user32.PrintWindow(hwnd, memdc.GetSafeHdc(), 2)
    if result == 1:
        bytes = bitmap.GetBitmapBits(True)
        img = Image.frombuffer('RGB', (width, height), bytes, 'raw', 'BGRX', 0, 1)
        img.save("file.bmp")
    #break
    
dc.DeleteDC()
memdc.DeleteDC()
win32gui.DeleteObject(bitmap.GetHandle())
win32gui.ReleaseDC(hwnd, hdc)

您也可以ctypes.windll.shcore.SetProcessDpiAwareness(2)在顶部添加


推荐阅读