pyvda
pyvda copied to clipboard
pywin32 is already a requirement, Can an hwnd_exists function be added to pyvda.py?
def hwnd_exists(hwnd) -> bool:
_exists = False
def enum_windows(hwnd, _hwnd):
nonlocal _exists
if hwnd == _hwnd:
_exists = True
win32gui.EnumWindows(enum_windows, hwnd)
return _exists
I used the pyvda.utils.Managers().view_collection.GetViewsByZOrder()
to get the hwnd, and with psutil.Process
to create a class that wraps the whole app. I have four windows of PyCharm open and this will return a screenshot of each window that is attached to pycharm64.exe
process.
import ctypes
import cv2 as cv
import numpy
import psutil
import pyvda
import pyvda.com_defns
import pyvda.utils
import win32con
import win32gui
import win32ui
class AppProcess(psutil.Process, pyvda.AppView):
def __init__(self, hwnd: int):
from win32process import GetWindowThreadProcessId as GetPID
psutil.Process.__init__(self, pid = GetPID(hwnd)[1])
pyvda.AppView.__init__(self, hwnd = hwnd)
@property
def window_title(self) -> str:
return win32gui.GetWindowText(self.hwnd)
@property
def name(self):
return psutil.Process.name(self)
@property
def screenshot(self):
def hwnd_exists(hwnd: int) -> bool:
_exists = False
def enum_windows(hwnd, _hwnd):
nonlocal _exists
if _hwnd == hwnd:
_exists = True
win32gui.EnumWindows(enum_windows, hwnd)
return _exists
def reshape(left: int, top: int, right: int, bottom: int):
return right - left, bottom - top
if not hwnd_exists(self.hwnd):
return numpy.array([])
ctypes.windll.user32.SetProcessDPIAware()
width, height = reshape(*win32gui.GetWindowRect(self.hwnd))
wdc = win32gui.GetWindowDC(self.hwnd)
dc = win32ui.CreateDCFromHandle(wdc)
cdc = dc.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(dc, width, height)
cdc.SelectObject(bitmap)
cdc.BitBlt((0, 0), (width, height), dc, (0, 0), win32con.SRCCOPY)
ctypes.windll.user32.PrintWindow(self.hwnd, cdc.GetSafeHdc(), 3)
_screenshot = numpy.frombuffer(bitmap.GetBitmapBits(True), dtype = numpy.uint8).reshape((height, width, 4))
dc.DeleteDC()
cdc.DeleteDC()
win32gui.ReleaseDC(self.hwnd, wdc)
win32gui.DeleteObject(bitmap.GetHandle())
return _screenshot
def get_handles_by_z_order():
_: list[int] = []
array = pyvda.utils.Managers().view_collection.GetViewsByZOrder()
for view in array.iter(pyvda.com_defns.IApplicationView):
if bool(view.GetShowInSwitchers()):
_.append(view.GetThumbnailWindow())
return _
if __name__ == '__main__':
for hwnd in get_handles_by_z_order().copy():
process = AppProcess(hwnd = hwnd)
if process.name == 'pycharm64.exe':
cv.imshow(winname = 'screenshot', mat = process.screenshot)
cv.waitKey()
To change it up a bit...
if __name__ == '__main__':
for hwnd in get_handles_by_z_order().copy():
process = AppProcess(hwnd = hwnd)
if process.name == 'ACMirage.exe':
screenshot = cv.resize(
src = process.screenshot,
dsize = (0, 0),
fx = 0.5,
fy = 0.5
)
cv.imshow(winname = 'screenshot', mat = screenshot)
cv.waitKey()
Anyway I see a point in having the def hwnd_exists(hwnd: int) -> bool:
function.