createDCFromHandle()/createCompatibleDC() 内存泄漏
Memory leak with createDCFromHandle()/ createCompatibleDC()
我正在尝试使用 GDI 捕获屏幕,我找到了一个代码片段并根据我的要求对其进行了修改。这是代码[编辑:为简单起见修改的代码]:
def getfunc():
# grab a handle to the main desktop window
hdesktop = win32gui.GetDesktopWindow()
# create a device context
desktop_dc = win32gui.GetWindowDC(hdesktop)
img_dc = win32ui.CreateDCFromHandle(desktop_dc)
# create a memory based device context
self.mem_dc = img_dc.CreateCompatibleDC()
# create a bitmap object
screenshot = win32ui.CreateBitmap()
screenshot.CreateCompatibleBitmap(img_dc, width, height)
self.mem_dc.SelectObject(screenshot)
# copy the screen into our memory device context
try:
self.mem_dc.BitBlt((destUpLeftX, destUpLeftY), (width, height), img_dc, (srcUpLeftX, srcUpLeftY),win32con.SRCCOPY)
except :
logger.debug("BitBlt failed")
img_dc.DeleteDC()
win32gui.ReleaseDC(hdesktop, desktop_dc)
win32gui.DeleteObject(screenshot.GetHandle())
def delete(self):
self.mem_dc.DeleteDC()
现在,当我尝试 运行 这段代码时,正好经过 80 次迭代。我收到错误提示 createDCFromHandle 失败或 createCompatibleDC 失败。
我寻找任何解决方案到达以下 Whosebug question
根据post,存在内存泄漏问题,我按照建议修改了我的删除功能。但我认为我仍然遗漏了任何相同的指针?
您稍后似乎要删除 mem_dc
。 screenshot
(位图)在 mem_dc
中仍处于选中状态,因此 screenshot
的删除延迟到 mem_dc
的删除。这可能 运行 会出现问题,具体取决于其余代码的设置方式。
您可以尽快从 mem_dc
中选择位图来消除风险。下面是一个如何做到这一点的例子。
请注意,您有 10,000 个 GDI 句柄的限制,因此您的代码不应在 80 次迭代后失败。问题可能出在其他地方。
hwnd = win32gui.GetDesktopWindow()
hdc = win32gui.GetWindowDC(hwnd)
memdc = win32gui.CreateCompatibleDC(hdc)
hbitmap = win32gui.CreateCompatibleBitmap(hdc, 100, 100)
oldbmp = win32gui.SelectObject(memdc, hbitmap)
win32gui.BitBlt(memdc, 0, 0, 100, 100, hdc, 0, 0, win32con.SRCCOPY)
#use memdc here
win32gui.SelectObject(memdc, oldbmp)
win32gui.DeleteObject(hbitmap)
win32gui.ReleaseDC(hwnd, hdc)
win32gui.DeleteDC(memdc)
替代方法
使用bits = GetBitmapBits
并使用
获取单个像素
p = (y * width + x) * 4
blue=bits[p+0]&0xFF
green=bits[p+1]&0xFF
red=bits[p+2]&0xFF
示例:
def foo(width, height):
hwnd = win32gui.GetDesktopWindow()
hdc = win32gui.GetWindowDC(hwnd)
dc = win32ui.CreateDCFromHandle(hdc)
memdc = dc.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(dc, width, height)
oldbmp = memdc.SelectObject(bitmap)
memdc.BitBlt((0,0), (width,height), dc, (0,0), win32con.SRCCOPY)
bits = bitmap.GetBitmapBits(False)
memdc.SelectObject(oldbmp)
win32gui.DeleteObject(bitmap.GetHandle())
memdc.DeleteDC()
win32gui.ReleaseDC(hwnd, hdc)
return bits
width = 100
height = 100
bits = foo(width,height)
for y in range(0,10):
for x in range(0,10):
p = (y * width + x) * 4
blu=bits[p+0]&0xFF
grn=bits[p+1]&0xFF
red=bits[p+2]&0xFF
print("%02X%02X%02X " % (blu,grn,red), end='')
print('')
我正在尝试使用 GDI 捕获屏幕,我找到了一个代码片段并根据我的要求对其进行了修改。这是代码[编辑:为简单起见修改的代码]:
def getfunc():
# grab a handle to the main desktop window
hdesktop = win32gui.GetDesktopWindow()
# create a device context
desktop_dc = win32gui.GetWindowDC(hdesktop)
img_dc = win32ui.CreateDCFromHandle(desktop_dc)
# create a memory based device context
self.mem_dc = img_dc.CreateCompatibleDC()
# create a bitmap object
screenshot = win32ui.CreateBitmap()
screenshot.CreateCompatibleBitmap(img_dc, width, height)
self.mem_dc.SelectObject(screenshot)
# copy the screen into our memory device context
try:
self.mem_dc.BitBlt((destUpLeftX, destUpLeftY), (width, height), img_dc, (srcUpLeftX, srcUpLeftY),win32con.SRCCOPY)
except :
logger.debug("BitBlt failed")
img_dc.DeleteDC()
win32gui.ReleaseDC(hdesktop, desktop_dc)
win32gui.DeleteObject(screenshot.GetHandle())
def delete(self):
self.mem_dc.DeleteDC()
现在,当我尝试 运行 这段代码时,正好经过 80 次迭代。我收到错误提示 createDCFromHandle 失败或 createCompatibleDC 失败。
我寻找任何解决方案到达以下 Whosebug question
根据post,存在内存泄漏问题,我按照建议修改了我的删除功能。但我认为我仍然遗漏了任何相同的指针?
您稍后似乎要删除 mem_dc
。 screenshot
(位图)在 mem_dc
中仍处于选中状态,因此 screenshot
的删除延迟到 mem_dc
的删除。这可能 运行 会出现问题,具体取决于其余代码的设置方式。
您可以尽快从 mem_dc
中选择位图来消除风险。下面是一个如何做到这一点的例子。
请注意,您有 10,000 个 GDI 句柄的限制,因此您的代码不应在 80 次迭代后失败。问题可能出在其他地方。
hwnd = win32gui.GetDesktopWindow()
hdc = win32gui.GetWindowDC(hwnd)
memdc = win32gui.CreateCompatibleDC(hdc)
hbitmap = win32gui.CreateCompatibleBitmap(hdc, 100, 100)
oldbmp = win32gui.SelectObject(memdc, hbitmap)
win32gui.BitBlt(memdc, 0, 0, 100, 100, hdc, 0, 0, win32con.SRCCOPY)
#use memdc here
win32gui.SelectObject(memdc, oldbmp)
win32gui.DeleteObject(hbitmap)
win32gui.ReleaseDC(hwnd, hdc)
win32gui.DeleteDC(memdc)
替代方法
使用bits = GetBitmapBits
并使用
p = (y * width + x) * 4
blue=bits[p+0]&0xFF
green=bits[p+1]&0xFF
red=bits[p+2]&0xFF
示例:
def foo(width, height):
hwnd = win32gui.GetDesktopWindow()
hdc = win32gui.GetWindowDC(hwnd)
dc = win32ui.CreateDCFromHandle(hdc)
memdc = dc.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(dc, width, height)
oldbmp = memdc.SelectObject(bitmap)
memdc.BitBlt((0,0), (width,height), dc, (0,0), win32con.SRCCOPY)
bits = bitmap.GetBitmapBits(False)
memdc.SelectObject(oldbmp)
win32gui.DeleteObject(bitmap.GetHandle())
memdc.DeleteDC()
win32gui.ReleaseDC(hwnd, hdc)
return bits
width = 100
height = 100
bits = foo(width,height)
for y in range(0,10):
for x in range(0,10):
p = (y * width + x) * 4
blu=bits[p+0]&0xFF
grn=bits[p+1]&0xFF
red=bits[p+2]&0xFF
print("%02X%02X%02X " % (blu,grn,red), end='')
print('')