def dumpWindow(hwnd): '''Dump all controls from a window into a nested list Useful during development, allowing to you discover the structure of the contents of a window, showing the text and class of all contained controls. Arguments: The window handle of the top level window to dump. Returns A nested list of controls. Each entry consists of the control's hwnd, its text, its class, and its sub-controls, if any. Usage example: replaceDialog = findTopWindow(wantedText='Replace') pprint.pprint(dumpWindow(replaceDialog)) ''' windows = [] try: win32gui.EnumChildWindows(hwnd, _windowEnumerationHandler, windows) except win32gui.error: # No child windows return windows = [list(window) for window in windows] for window in windows: childHwnd, windowText, windowClass = window window_content = dumpWindow(childHwnd) if window_content: window.append(window_content) return windows
def searchChildWindows(currentHwnd): results = [] childWindows = [] try: win32gui.EnumChildWindows(currentHwnd, _windowEnumerationHandler, childWindows) except win32gui.error: # This seems to mean that the control *cannot* have child windows, # i.e. not a container. return for childHwnd, windowText, windowClass in childWindows: descendentMatchingHwnds = searchChildWindows(childHwnd) if descendentMatchingHwnds: results += descendentMatchingHwnds if wantedText and \ not _normaliseText(wantedText) in _normaliseText(windowText): continue if wantedClass and \ not windowClass == wantedClass: continue if selectionFunction and \ not selectionFunction(childHwnd): continue results.append(childHwnd) return results
def click(self, x, y): if self.click_by_mouse: window_title = self._getWindowTitle() try: hwin = win32gui.FindWindow('LDPlayerMainFrame', window_title) self._subhwin = None def winfun(hwnd, lparam): subtitle = win32gui.GetWindowText(hwnd) if subtitle == 'TheRender': self._subhwin = hwnd win32gui.EnumChildWindows(hwin, winfun, None) ret = win32gui.GetWindowRect(self._subhwin) height = ret[3] - ret[1] width = ret[2] - ret[0] tx = int(x * width / constants.BASE_WIDTH) ty = int(y * height / constants.BASE_HEIGHT) positon = win32api.MAKELONG(tx, ty) win32api.SendMessage(self._subhwin, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, positon) win32api.SendMessage(self._subhwin, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, positon) except Exception as e: print(f"fallback adb click:{e}") super().click(x, y) else: super().click(x, y)
def print_window_info(cls, win, depth=5000, pre_fix_str='', screen_shot_save_path=None): """ 打印指定窗口信息(含子控件) @param {WindowControlSpec} win - 要打印信息的窗口对象 @param {int} depth=5000 - 最大窗口搜索深度(数量) @param {str} pre_fix_str='' - 打印信息前的缩进字符串 @param {str} screen_shot_save_path=None - 截图保存路径, 非None时代表进行截图 """ # 先打印当前窗口信息 win: WindowControlSpec _parent = win.parent if _parent is None: _parent_handle = 0 else: _parent_handle = _parent.handle print( '%s__handle:%s(%#x) pid:%s(%#x) name:%s class_name:%s parent:%s(%#x) rect:%s' % (pre_fix_str, str(win.handle), win.handle, str( win.process_id), win.process_id, win.name, win.class_name, str(_parent_handle), _parent_handle, str(win.win_rect))) if screen_shot_save_path is not None: # 进行控件的屏幕截图,先将窗口设置最前面 win.set_foreground() l, t, r, b = win.win_rect try: Screen.screenshot(image_save_file=os.path.join( screen_shot_save_path, '%s.jpg' % str(win.handle)), region=(l, t, r - l, b - t)) except SystemError: print('save_screen_shot_err: ', win.win_rect) # 判断是否要打印子窗口 if depth > 1: # 处理参数 _enum_para = { 'depth': depth, 'current_depth': 1, 'screen_shot_save_path': screen_shot_save_path, 'pre_fix_str': { win.handle: '' } } try: # 搜索子窗口对象 win32gui.EnumChildWindows( win.handle, cls._enum_child_windows_print_call_back, _enum_para) except: pass
def child_handle_list(hwnd: int) -> List[int]: """부모 핸들로부터 자식핸들 리스트를 가져옴 Args: hwnd: 부모 윈도우 핸들 Returns: 자식핸들 ID 리스트 """ enum = lambda x, arr: arr.append(x) out: List[HWND] = [] win32gui.EnumChildWindows(hwnd, enum, out) return out
def find_window(cls, **kwargs): """ 查找指定的窗口 @param {kwargs} - 具体实现类的扩展参数 muti_search {bool} - 是否返回所有匹配结果,默认为False,仅返回第一个结果 handle {int} - 窗口句柄, 如果指定该参数则直接获取该句柄的窗口, 不处理其他参数 top_level_only {bool} - 仅限顶级元素(默认值=True), 如果指定该参数则仅使用class_name、name检索顶层窗口, 不处理其他参数 class_name {str} - 窗口的类名(可通过spy++获取到) name {str} - 窗口标题 depth {int} - 最大搜索深度(数量,默认值5000) class_name_re {str} - 类与此正则表达式匹配的元素 name_re {str} - 文本与此正则表达式匹配的元素 parent {int} - 父窗口对象(句柄或WindowControlSpec对象) process {int} - 窗口所在的应用进程对象(进程ID) visible_only {bool} - 仅可见元素 (默认值=False) enabled_only {bool} - 仅启用元素 (默认值=False) active_only {bool} - 仅限活动元素(默认= False) @returns {WindowControlSpec|list} - 返回窗口对象,如果muti_search为True则返回匹配到的窗口数组 """ # 默认参数处理 _kwargs = { 'muti_search': False, 'class_name': None, 'name': None, 'depth': 5000, 'top_level_only': True, 'visible_only': False, 'enabled_only': False, 'active_only': False, } _kwargs.update(kwargs) # 直接给了窗口句柄,忽略其他条件 if 'handle' in _kwargs.keys(): if _kwargs['muti_search']: return [ WindowControlSpec(handle=kwargs['handle']), ] else: return WindowControlSpec(handle=kwargs['handle']) # 只查找顶级元素 if _kwargs['top_level_only']: _hwnd = win32gui.FindWindow(_kwargs['class_name'], _kwargs['name']) if _hwnd == 0: if _kwargs['muti_search']: return [] else: # 找不到窗口抛出异常 raise base_control.WindowException('Window not Found') if _kwargs['muti_search']: return [ WindowControlSpec(handle=_hwnd), ] else: return WindowControlSpec(handle=_hwnd) # 遍历方式查找 _enum_para = { 'search_para': _kwargs, # 传入的匹配参数 'current_depth': 0, # 当前搜索数量 'windows': [] # 存储返回的对象 } if 'parent' in _kwargs.keys(): # 有主窗口的情况 try: win32gui.EnumChildWindows(_kwargs['parent'], cls._enum_windows_call_back, _enum_para) except: # 如果回调函数返回False,将会抛出异常,需要屏蔽处理 pass else: # 从主窗口开始遍历查找 try: win32gui.EnumWindows(cls._enum_windows_call_back, _enum_para) except: # 如果回调函数返回False,将会抛出异常,需要屏蔽处理 pass # 再遍历查找子窗口 if len(_enum_para['windows']) == 0 or _kwargs['muti_search']: _enum_para_child = { 'search_para': _kwargs, # 传入的匹配参数 'current_depth': _enum_para['current_depth'], # 当前搜索数量 'windows': [] # 存储返回的对象 } for _win in _enum_para['windows']: try: win32gui.EnumChildWindows(_win.handle, cls._enum_windows_call_back, _enum_para_child) if not _kwargs['muti_search'] and len( _enum_para_child['windows']) > 0: break except: # 如果回调函数返回False,将会抛出异常,需要屏蔽处理 pass # 合并两个数组 _enum_para['windows'].extend(_enum_para_child['windows']) # 返回结果 if _kwargs['muti_search']: return _enum_para['windows'] else: if len(_enum_para['windows']) > 0: return _enum_para['windows'][0] else: # 找不到窗口抛出异常 raise base_control.WindowException('Window not Found')
def demo_child_windows(self, parent): if not parent: return hWndChildList = [] win32gui.EnumChildWindows(parent, lambda hWnd, param: param.append(hWnd), hWndChildList) return hWndChildList
# 获取窗口位置 left, top, right, bottom = win32gui.GetWindowRect(handle) #获取某个句柄的类名和标题 title = win32gui.GetWindowText(handle) clsname = win32gui.GetClassName(handle) # 打印句柄 # 十进制 print(handle) # 十六进制 print("%x" % (handle)) # 搜索子窗口 # 枚举子窗口 hwndChildList = [] win32gui.EnumChildWindows(handle, lambda hwnd, param: param.append(hwnd), hwndChildList) # FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None) 父窗口句柄 若不为0,则按照z-index的顺序从hwndChildAfter向后开始搜索子窗体,否则从第一个子窗体开始搜索。 子窗口类名 子窗口标题 subHandle = win32gui.FindWindowEx(handle, 0, "EDIT", None) # 获得窗口的菜单句柄 menuHandle = win32gui.GetMenu(subHandle) # 获得子菜单或下拉菜单句柄 # 参数:菜单句柄 子菜单索引号 subMenuHandle = win32gui.GetSubMenu(menuHandle, 0) # 获得菜单项中的的标志符,注意,分隔符是被编入索引的 # 参数:子菜单句柄 项目索引号 menuItemHandle = win32gui.GetMenuItemID(subMenuHandle, 0) # 发送消息,加入消息队列,无返回 # 参数:句柄 消息类型 WParam IParam win32gui.postMessage(subHandle, win32con.WM_COMMAND, menuItemHandle, 0)