一招让Windows FindWindow函数更好用
我们通过python来开发自动化或者RPA工具时,经常需要用到大名鼎鼎的pywin32库。里面有诸如sendMessage、PostMessage、FindWindow、FindwindowEx、EnumWindows等大票好用的windows系统API函数。提到Findow函数,就不得不提及它的一大缺憾:不支持基于窗口标题关键字模糊查找。
我们先来认识下今天的主角FindWindow函数。
MSDN中的解释如下:
简单地说,该函数检索处理顶级窗口的类名和窗口名称匹配指定的字符串,并不会搜索子窗口。
它的C++参数构成如下:
HWND FindWindowA( [in, optional] LPCSTR lpClassName, [in, optional] LPCSTR lpWindowName );
再来看下它的返回值:
如果函数执行成功,它会返回包含指定类名和窗口名的窗口对应的句柄,如果失败,则返回Null。
认识了该函数之后,我们再回到文章开头提到的痛点,如何让该函数支持基于窗口标题模糊查找呢?
大体的思路是,利用EnumWindows函数得到所有顶级窗口的句柄,再通过GetClassName、GetWindowText等函数依次拿到对应窗口的类名、标题,并与我们预设的类名、窗口名关键字进行匹配,如果能关联到,返回对应的窗口句柄即可,我们需要的是这样一个人性化的FindWindow函数,姑且取名find_window_wildcard,说干就干,下面是具体的实现过程。
1 import win32gui,re 2 class WindowMgr: 3 """Encapsulates some calls to the winapi for window management""" 4 5 def __init__ (self): 6 """Constructor""" 7 self._handle = None 8 9 def find_window(self, class_name, window_name=None): 10 """基于类名来查找窗口""" 11 self._handle = win32gui.FindWindow(class_name, window_name) 12 13 def _window_enum_callback(self, hwnd, class_name_wildcard_list): 14 """传递给win32gui.EnumWindows(),检查所有打开的顶级窗口""" 15 class_name,wildcard=class_name_wildcard_list 16 if win32gui.GetClassName(hwnd)==class_name and re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None: 17 self._handle = hwnd 18 19 def find_window_wildcard(self, class_name,wildcard): 20 """根据类名,查找一个顶级窗口,确保其类名相符,且标题可以用正则表达式匹配对应的通配符""" 21 self._handle = None 22 win32gui.EnumWindows(self._window_enum_callback,[class_name, wildcard]) 23 return self._handle 24 25 def set_foreground(self): 26 """put the window in the foreground""" 27 win32gui.SetForegroundWindow(self._handle) 28 29 def get_hwnd(self): 30 """return hwnd for further use""" 31 return self._handle 32 if __name__=="__main__": 33 myWindowMgr=WindowMgr() 34 '''查找一个类名为XLMAIN,窗口标题中含【银行余额】字符串的窗口,并返回它的句柄;如果没找到,返回None''' 35 excelHwnd=myWindowMgr.find_window_wildcard("XLMAIN",".*?银行余额.*?") 36 print(excelHwnd)
各位筒子赶紧试试,试完你一定会回来感谢我的,相信我~~
快来扫码关注我的公众号 获取更多爬虫、数据分析的知识!