[Python进阶] WindowsAPI:pywin32.win32gui

6.25 WindowsAPI:pywin32.win32gui

win32gui中定义了一些有关图形操作的API,例如FindWindow、PostMessage等。win32gui中的API多达几百个,这里我们挑选一些比较重要且常用的来介绍。

6.25.1 FindWindow

通过类名和标题搜索窗体并返回句柄

FindWindow(lpClassName=None, lpWindowName=None)

描述:

自顶层窗口(也就是桌面)开始搜索条件匹配的窗体,并返回这个窗体的句柄。不搜索子窗口、不区分大小写。找不到就返回0

参数:

lpClassName:字符型,是窗体的类名,这个可以在Spy++里找到。

lpWindowName:字符型,是窗口名,也就是标题栏上你能看见的那个标题。

说明:

1、找到了主窗口以后就靠它来定位子窗体,该函数只能搜索顶层窗口。

2、若子窗口不以窗口句柄的形式创建(windowless),只是逻辑上的窗口,绘制在父窗口之上。这种情况是只能定位到主窗口的。比如微信。

3、若lpClassName=None或lpWindowName=None,则表示对这两个参数不做匹配要求,返回第一个匹配到的窗口。

窗口的类名和打开的程序相关,和文件无关。如下:

文件格式/程序 类名
记事本 Notepad
360浏览器 360se6_Frame
IE浏览器 IEFrame
Excel2016标准版 XLMAIN
UC wxWindowNR
谷歌浏览器 Chrome_WidgetWin_1
pycharm SunAwtFrame
word2016标准版 OpusApp
微信 WeChatMainWndForPC
百度云盘 DuiHostWnd
Notepad++ Notepad++
企业微信 WeWorkWindow

示例1:通过类和标题查找企业微信窗口句柄

py 复制代码
import win32gui
from icecream import ic

handle = win32gui.FindWindow('WeWorkWindow', '企业微信')
ic(handle, hex(handle))

11:03:54|> handle: 68028, hex(handle): '0x109bc'

示例2:通过类查找谷歌浏览器窗口句柄

py 复制代码
import win32gui
from icecream import ic

handle = win32gui.FindWindow('Chrome_WidgetWin_1', None)
ic(handle, hex(handle))

11:06:18|> handle: 66520, hex(handle): '0x103d8'

这里同时也输出了目标窗口句柄的16进制,方便和spy++软件查找的结果对照。

6.25.2 FindWindowEx

检索其类名和窗口名称与指定字符串匹配的窗口的句柄。该函数搜索子窗口,从给定的子窗口之后开始。

参数:

hwndParent:标识要搜索子窗口的父窗口。如果【hwndParent】为None,该函数将使用桌面窗口作为父窗口。该函数将在桌面的子窗口中进行搜索。

hwndChildAfter:标识子窗口。搜索从Z顺序中的下一个子窗口开始。【hwndChildAfter】必须是【hwndParent】的直接子窗口,而不仅仅是后代窗口。如果【hwndChildAfter】为None,则搜索从第一个子窗口【hwndParent】开始。请注意,如果【hwndParent】和【hwndChildAfter】均为None,则该函数将搜索所有顶级窗口。

lpszClasspl:要搜索的窗口类名。

lpszWindow:要搜索的窗口标题。

注意:

若lpszClasspl =None或lpszWindow =None,则表示对这两个参数不做匹配要求,返回第一个匹配到的窗口。

py 复制代码
import win32gui
from icecream import ic

handle = win32gui.FindWindowEx(None, None, 'Notepad', None)  # 在顶层窗口中搜索`记事本`窗口
ic(handle, hex(handle))
handle = win32gui.FindWindowEx(handle, None, 'Edit', None)  # 在`记事本`窗口中搜索`Edit`窗口
ic(handle, hex(handle))

11:25:40|> handle: 659030, hex(handle): '0xa0e56'

11:25:40|> handle: 855762, hex(handle): '0xd0ed2'

6.25.3 GetParent

获取子窗口的父窗口句柄

py 复制代码
import win32gui

child_handle = 69136
parent_handle = win32gui.GetParent(child_handle)
print(parent_handle)

6.25.4 GetWindowRect

返回窗口的边界矩形的尺寸。尺寸以相对于屏幕左上角的屏幕坐标给出。

注意:窗口不能是最小化到任务栏,否则返回的尺寸会是负数。

py 复制代码
import win32gui
from icecream import ic

handle = win32gui.FindWindowEx(None, None, 'Notepad', None)  # 在顶层窗口中搜索`记事本`窗口
ic(handle, hex(handle))
left, top, right, bottom = win32gui.GetWindowRect(handle)
ic(left, top, right, bottom)

11:29:24|> handle: 659030, hex(handle): '0xa0e56'

11:29:24|> left: 843, top: 132, right: 1502, bottom: 698

6.25.5 GetWindowText

获取窗口标题

py 复制代码
import win32gui
from icecream import ic

handle = win32gui.FindWindowEx(None, None, 'Notepad', None)
ic(handle, hex(handle))
title = win32gui.GetWindowText(handle)
ic(title)

11:30:48|> handle: 659030, hex(handle): '0xa0e56'

11:30:48|> title: 'Temp.txt - 记事本'

6.25.6 GetClassName

获取窗口的类

py 复制代码
import win32gui

handle = 201008
class_name = win32gui.GetClassName(handle)
print(class_name)

6.25.7 IsWindow

判断某个整数是否是一个窗口的句柄。若是,则返回值不为0,否则返回0。

win32gui.IsWindow(hwnd)

6.25.8 IsWindowEnabled

确定是否为鼠标和键盘输入启用了指定的窗口。窗口可用。

返回值:如果启用该窗口,则返回值不为零。如果窗口未启用,返回值为零。

备注:子窗口只有在启用和可见时才接收输入。

win32gui.IsWindowEnabled(hwnd)

6.25.9 IsWindowVisible

检索指定窗口的可见性状态(是否具有WS_VISIBLE样式)。

返回值:

如果指定的窗口及其父窗口具有WS_VISIBLE样式,则返回值不为零。

如果指定的窗口及其父窗口没有WS_VISIBLE样式,返回值为零。

因为返回值指定窗口是否具有WS_VISIBLE样式,即使窗口完全被其他窗口遮挡,它也可能非零。

备注

窗口的可见性状态由WS_VISIBLE样式位指示。设置WS_VISIBLE时,只要窗口具有WS_VISIBLE样式,将显示该窗口,并显示其后续绘图。

如果窗口被其他窗口遮挡或被其父窗口剪裁,任何绘制到具有WS_VISIBLE样式的窗口将不会显示。

win32gui.IsWindowVisible(hwnd)

6.25.10 EnumWindows

通过将每个窗口的句柄依次传递给应用程序定义的回调函数来枚举屏幕上的所有顶级窗口。EnumWindows继续,直到最后一个顶级窗口被枚举或回调函数返回FALSE。
示例1:遍历windows下所有句柄及窗口名称

py 复制代码
from icecream import ic
import win32gui

hwnd_title = dict()


def get_all_hwnd(hwnd, mouse):
    if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
        hwnd_title.update({hwnd: win32gui.GetWindowText(hwnd)})


win32gui.EnumWindows(get_all_hwnd, 0)
for handle, title in hwnd_title.items():
    if title:
        ic(handle, title)

15:20:14|> handle: 986708, title: 't1.py -- t5.py'

15:20:14|> handle: 921718, title: 'Python - 进阶.docx - Word'

15:20:14|> handle: 659030, title: 'Temp.txt - 记事本'

15:20:14|> handle: 1577106, title: '查找窗口'

15:20:14|> handle: 67000, title: '企业邮箱前台-邮箱 - 360安全浏览器 14.1'

15:20:14|> handle: 394748, title: '数据驱动.xlsm - Excel'

15:20:14|> handle: 68028, title: '企业微信'

15:20:14|> handle: 133664, title: 'PythonFiles'

15:20:14|> handle: 983950, title: 'spy - Everything'

15:20:14|> handle: 327756, title: 'Microsoft Text Input Application'

15:20:14|> handle: 68710, title: '非常用工作文档.xlsm - Excel'

15:20:14|> handle: 66004, title: 'Program Manager'

示例2:通过窗体标题模糊搜索并返回窗体句柄

py 复制代码
from icecream import ic
import win32gui

hwnd_title = dict()


def get_all_hwnd(hwnd, mouse):
    if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
        hwnd_title.update({hwnd: win32gui.GetWindowText(hwnd)})


win32gui.EnumWindows(get_all_hwnd, 0)


def find_window(part_title):
    for hwnd, title in hwnd_title.items():
        if part_title in title:
            return hwnd


handle = find_window('企业微信')
ic(handle)

15:24:17|> handle: 68028

6.25.11 EnumChildWindows

通过将每个子窗口的句柄传递给应用程序定义的回调函数来枚举属于指定父窗口的子窗口,直到最后一个子窗口被枚举或回调函数返回FALSE。
示例1:获取主窗口句柄下的所有子孙窗口句柄

py 复制代码
from icecream import ic
import win32gui

parent_handle = int('000A0E56', 16)


def get_children_window(parent):
    hwndChildList = []
    win32gui.EnumChildWindows(parent, lambda hwnd, param: param.append(hwnd), hwndChildList)
    return hwndChildList


child_list = get_children_window(parent_handle)
ic(child_list)

15:27:14|> child_list: [855762, 201106]

6.25.12 ShowWindow

激活显示窗口,根据第二个参数的不同改变窗口的不同状态。

py 复制代码
import win32gui
import win32con

hwnd = 3806050
win32gui.ShowWindow(hwnd, win32con.SW_SHOWNORMAL)

其中ShowWindow 函数显示方式(第二个参数)定义如下

参数(win32con) 意义 备注
SW_HIDE 隐藏窗口,大小不变,激活状态不变 不光是窗口最小化,连任务栏里都不会存在
SW_MAXIMIZE 最大化窗口,显示状态不变,激活状态不变
SW_MINIMIZE 最小化窗口,显示状态不变,激活状态不变 最小化窗口
SW_RESTORE 从最大化或最小化恢复正常大小,显示状态不变,激活状态不变 窗口恢复正常
SW_SHOW 显示并激活窗口,大小状态不变 sw_hide的反向操作。不过只是会在任务栏中显示,桌面上看不到窗口
SW_SHOWMAXIMIZED 显示并激活窗口,以最大化显示
SW_SHOWMINIMIZED 显示并激活窗口,以最小化显示
SW_SHOWMINNOACTIVE 显示窗口并最小化,激活状态不变
SW_SHOWNA 显示窗口,大小状态不变,激活状态不变 和sw_show一样,没看出什么区别
SW_SHOWNOACTIVATE 显示并从最大化或最小化恢复正常大小,激活状态不变 显示窗口到正常大小,但不会前置
SW_SHOWNORMAL 显示并激活窗口,恢复正常大小(初始化时用这个参数) 显示窗口到正常大小,但不会前置

6.25.13 SetForegroundWindow

前置窗口

win32gui.SetForegroundWindow(hwnd)

6.25.14 Postmessage、SendMessage

函数功能:

该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,Postmessage不等待线程处理消息就返回。而SendMessage则会一直等待处理完并返回处理结果。消息队列里的消息通过调用GetMessagePeekMessage取得。
函数原型:

B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);

LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:

hWnd:其窗口程序接收消息的窗口的句柄。

Msg:指定被寄送的消息。

wParam:指定附加的消息特定的信息。

IParam:指定附加的消息特定的信息。

返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。

py 复制代码
import win32gui

hwnd = int('000E0EE2', 16)
win32gui.SendMessage(0x00041192, win32con.WM_SETTEXT, None, 'hello world')  # 将hello world写入到记事本中
win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_F5, 0)  # 发送F5键到记事本中,将会写入当前时间
win32api.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_F5, 0)
win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)  # 关闭窗口,将会询问是否要保存
相关推荐
努力进修26 分钟前
欢迎来到我的Java世界“抽象类”
java·开发语言·python
FreakStudio3 小时前
全网最适合入门的面向对象编程教程:48 Python函数方法与接口-位置参数、默认参数、可变参数和关键字参数
python·嵌入式·面向对象·电子diy
天下无敌笨笨熊4 小时前
PyQT开发总结
python·pyqt
机器学习Zero4 小时前
让效率飞升的秘密武器:解锁编程高效时代的钥匙
git·python·github·aigc
wjcroom4 小时前
celery-APP在windows平台的发布方法(绿色免安装exe可搭配eventlet)
windows·python·celery
AI让世界更懂你5 小时前
漫谈设计模式 [5]:建造者模式
python·设计模式·建造者模式
FutureUniant5 小时前
GitHub每日最火火火项目(9.13)
人工智能·python·计算机视觉·github·音视频
liuzhenghua666 小时前
python运维
运维·开发语言·python
学java的小菜鸟啊6 小时前
Java队列详细解释
java·开发语言·经验分享·python
ac-er88886 小时前
什么是Flask-WTF
后端·python·flask