-想整个QQ自动发消息的,于是找到了这个,这个模块呢就是用来调用window系统的API,来打开个程序,自动发个消息之类的,更高级的线程进程啥的咱也不会。。。
链接: https://pan.baidu.com/s/1mqrFYh3TGUVQ8gIcXoJ1BQ 提取码: fr9x pywin32 的帮助文档,,,
链接: https://pan.baidu.com/s/1U26Q23JqJblrUIfvGBZSQw 提取码: h5vq spy++的
参考脑补链接
消息是系统定义的一个32位值,定义了一个事件。消息的结构(MSG):
typedef struct tagMsg
{
HWND hwnd; //接受该消息的窗口句柄,就是消息所属的窗口,一般是16进制的一堆数,表示这资源内存的标识号
UINT message; //消息常量标识符,也就是我们通常所说的消息号,其实就是一些常量,也就五千多个吧。。
WPARAM wParam; //32位消息的特定附加信息,确切含义依赖于消息值,
LPARAM lParam; //32位消息的特定附加信息,确切含义依赖于消息值
DWORD time; //消息创建时的时间
POINT pt; //消息创建时的鼠标/光标在屏幕坐标系中的位置
}MSG;
消息标识符:WM_NULL—0x0000 空消息。具体的查询就要看MSDN了(微软的开发文档)
这里面还可以查询所有消息的,wParam and lParam。感觉不错。。。。就是没有中文。。。
当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动程序就会把这些事件转换成相应的消息,然后输送到系统消息队列,由
Windows系统去进行处理。Windows系统则在适当的时机,从系统消息队列中取出一个消息,根据前面我们所说的MSG消息结构确定消息是要被送往那个窗口,然后把取出的消息送往创建窗口的线程的相应队列,下面的事情就该由线程消息队列操心了,Windows开始忙自己的事情去了。线程看到自己的消息队列中有消息,就从队列中取出来,通过操作系统发送到合适的窗口过程去处理。
网上实在找不到全面的教程,,,至于帮助文档,,各种模块的方法倒是很全,但是完全没讲怎么和消息的结合,自带的例子,,呵呵看不懂。所以就尽量把所有能找到的实例研究一遍,估计常用的方法也差不多了,毕竟超超超极多的消息和方法也没打算全记住。。。
win32api 提供了常用的用户API
win32clipboard 提供了有关粘贴板的API
win32gui 提供了有关windows用户界面图形操作的API
win32file 提供了有关文件操作的API
win32con 有关的消息常量,,,感觉这些模块都好用欸,,一步一步来吧
这个软件是来看窗口的句柄,类名的,很好用啊,不过人家说是 VC 自带的,我咋没有呢。。。
参考脑补连接
参考脑补连接
import win32gui # 先来小小的体验一下
import win32con
win = win32gui.FindWindow('Notepad','新建文本文档.txt - 记事本') # 找到这个文件,里面的参数都是再spy++ 里面找的
tid = win32gui.FindWindowEx(win,None,'Edit',None) # 主窗口下的子窗口
win32gui.SendMessage(tid, win32con.WM_SETTEXT, None, '呐呐呐') # 写入字段
win32gui.PostMessage(tid,win32con.WM_KEYDOWN,win32con.VK_RETURN,0) # 插入一个回车
下面就是我再这个例子中学到的一些函数和消息。参考这位大佬写的四篇文章,,可惜不更新了
win32api.ShellExecute int = ShellExecute(hwnd, op , file , params ,
dir , bShow ) 打开或打印一个文件。 Parametershwnd : PyHANDLE
父窗口的句柄,如果没有父窗口,则为0。该窗口接收应用程序生成的任何消息框(例如,用于错误报告)。
op : string
要执行的操作。可以是“打开”,“打印”或“无”,默认为“打开”。
file : string 文件名
params : string
如果文件名包含可执行文件,则传递的参数。对于文档文件,应为None。
dir : string
应用程序的初始目录。
bShow : int
指定在打开应用程序时是否显示该应用程序。如果lpszFile参数指定一个文档文件,则此参数为零。
win32api.Sleep
int = Sleep(time, bAlterable )在指定的时间内暂停当前线程的执行。
Parameters
time : int
The number of milli-seconds to sleep for,
bAlterable=0 : int
指定该函数是否可能由于I / O完成回调函数而提前终止。
Return Value 如果指定的时间间隔到期,则返回值为零。
win32gui.FindWindow PyHANDLE = FindWindow(ClassName, WindowName )
检索顶级窗口的句柄,该窗口的类名和窗口名与指定的字符串匹配。Parameters
ClassName : 要查找的窗口类的名,可以为None
WindowName : 查找窗口的标题,可以为None
win32gui.FindWindowEx PyHANDLE = FindWindowEx(Parent, ChildAfter , ClassName , WindowName )
Parameters
Parent : PyHANDLE 将搜索其子窗口的窗口。如果为0,则假定为桌面窗口。
ChildAfter : PyHANDLE 以Z顺序搜索之后的子窗口,可以为0以搜索所有子窗口
ClassName :
WindowName :
save_path = r'C:\Users\NERO\Desktop\栗子一.txt' # 这个也是以后保存的文件名
notepad_path=r'C:\Windows\notepad.exe' # 这个是记事本应用的路径
win32api.ShellExecute(0,'open',notepad_path,'','',1)
sasveas_posilst=[0,3]
while True:
win = win32gui.FindWindow('Notepad','') # 来个循环,等待窗口的开启。
if win != 0: # 如果开启win 就是这个窗口的句柄了。
win32api.Sleep(200)
print('启动成功',win)
break
win32gui.SendMessage int = SendMessage(hwnd, message , wparam , lparam )
Sends a message to the window.
Parameters
hwnd : int
The handle to the Window
message : int
The ID of the message to post
wparam=None : int/str
Type depends on the message
lparam=None : int/str
Type depends on the message
edit_handle = win32gui.FindWindowEx(win,0,'Edit',None) # 找到子窗口,输入文字,这个Edit 再spy++ 里获得。
print(edit_handle)
win32gui.SendMessage(edit_handle,win32con.WM_SETTEXT,None,'现在我很困啊')
WM_SETTEXT message
wParam
不使用此参数。
lParam
指向以空值结尾的字符串的指针,该字符串是窗口文本。
将指定的消息发送到一个或多个窗口。该SendMessage函数的函数调用指定的窗口的窗口过程,并不会返回,直到窗口过程已经处理了该消息。 要发送消息并立即返回,请使用SendMessageCallback或SendNotifyMessage函数。
要将消息发布到线程的消息队列中并立即返回,只是把消息放入队列,不管其他程序是否处理都返 回,然后继续执行,请使用PostMessage或PostThreadMessage函数。
在控制别的应用程序的时候,经常需要等待直到某个功能结束,例如:
打开一个窗口–>等待直到窗口结束
这 个时候就可以用到SendMessage --------------------------------------------> SendMessage消息是同步的
如果在打开这个窗口后仍然需要对该窗口的界面进行设置,比如Edit的value等等,比如:
打 开一个窗口–>控制窗口的control的属性
这个时候就需要PostMessage --------------------------------------------> PostMessage消息是异步的
win32gui.PostMessage PostMessage(hwnd, message, wparam, lparam) 在消息队列中加入为指定的窗体加入一条消息,并马上返回,不等待线程对消息的处理。 Parameters
hwnd : int
The handle to the Window
message : int
The ID of the message to post
wparam=0 : int
An integer whose value depends on the message
lparam=0 : int
An integer whose value depends on the message
GetMenu(hwnd)
描述:获取窗口的菜单句柄。
参数:
hwnd:整型,需要获取菜单的窗口的句柄。
说明:获取的是插图中黄色的部分。
GetSubMenu(hMenu, nPos)
描述:获取菜单的下拉菜单或者子菜单。
参数:
hMenu:整型,菜单的句柄,从GetMenu获得。
nPos:整型,下拉菜单或子菜单的的索引,从0算起。
说明:这个可以获取插图中蓝色的部分z;如描述所述,这个不仅可以获取本例中的下拉菜单,还可以获取子菜单。
GetMenuItemID(hMenu, nPos)
描述:获取菜单中特定项目的标识符。
参数:
hMenu:整型,包含所需菜单项的菜单句柄,从GetSubMenu获得。
nPos:整型,菜单项的索引,从0算起。
说明:这个获取的就是红色区域中的项目啦,注意,分隔符是被编入索引的,所以退出就是8,那几条线也算的。
menu_handle = win32gui.GetMenu(win)
menu_handle = win32gui.GetSubMenu(menu_handle,0)
com_ID = win32gui.GetMenuItemID(menu_handle,3)
win32gui.PostMessage(win,win32con.WM_COMMAND,com_ID,0) # 不明白 WM_COMMAND的参数这么些,去MSDN搜吧,,
# 通过postmessage 来打开了另存为这个窗口。
while True:
if win32gui.FindWindow(None, '另存为')!=0:
win32api.Sleep(2000)
print('另存为打开成功')
break
else:
win32api.Sleep(200)
可以看到,当WM_COMMAND操作菜单时,wparm就是菜单标识符(高字节低字节的问题一会再说),Iparam0
本来不想用函数的,奈何人家写的函数太香了,,,,总的来一遍吧。。
save_path = r'C:\Users\NERO\Desktop\test.txt'
notepad_path=r'C:\Windows\notepad.exe'
win32api.ShellExecute(0,'open',notepad_path,'','',1)
sasveas_posilst=[0,3]
while True:
win = win32gui.FindWindow('Notepad','')
if win != 0:
win32api.Sleep(200)
print('启动成功',win)
break
edit_handle = win32gui.FindWindowEx(win,0,'Edit',None)
print(edit_handle)
win32gui.SendMessage(edit_handle,win32con.WM_SETTEXT,None,'现在我很困啊')
menu_handle = win32gui.GetMenu(win)
menu_handle = win32gui.GetSubMenu(menu_handle,0)
com_ID = win32gui.GetMenuItemID(menu_handle,3)
win32gui.PostMessage(win,win32con.WM_COMMAND,com_ID,0) # 这里用SendMessage 为啥不行呢。。。就打不开这个窗口
# 我感觉应该是SendMessage 要等消息返回才继续,否则处于堵塞状态吧。。。
while True:
if win32gui.FindWindow(None, '另存为')!=0: # 这里的循环就是等待postmessage发送的消息执行
win32api.Sleep(2000)
print('另存为打开成功')
break
else:
win32api.Sleep(200)
save_win = win32gui.FindWindow(None, '另存为')
# save_name_handle = win32gui.FindWindowEx(save_win,0,'Edit','*.txt')
# win32gui.SendMessage(save_name_handle,win32con.WM_SETTEXT,None,save_path)
# 姑且试了下,那个文件名的框框再好几层下面,,直接是找不到的要一层一层下去,这就麻烦了,不过人家用递归写的函数,,精彩!!!
save_name_handle = find_handle_by_wndlist(save_win, [('DUIViewWndClassName',0),('DirectUIHWND',0),\
('FloatNotifySink',0),('ComboBox',0),('Edit',0)])
win32gui.SendMessage(save_name_handle,win32con.WM_SETTEXT,None,save_path) # 这里就可以把我们的文件名填进去了
comboBox_handle = find_handle_by_wndlist(save_win, [('ComboBox', 0)]) # 找到comboBox的句柄
select_comboBox_item(save_win,comboBox_handle,3) # 这就是对编码的选择
save_btn_handle = find_handle_by_wndlist(save_win, [('Button', 0)]) # 找到确定按钮的句柄
win32api.SendMessage(save_win,win32con.WM_COMMAND,win32con.VK_LBUTTON,save_btn_handle) # 执行点击操作,看不懂可以看靠下面的解析。
def find_idxSubHandle(pHandle, winClass, index=0): # 还带索引的功能,真香,,,,,
"""
已知子窗口的窗体类名
寻找第index号个同类型的兄弟窗口
"""
assert type(index) == int and index >= 0
handle = win32gui.FindWindowEx(pHandle, 0, winClass, None)
while index > 0:
handle = win32gui.FindWindowEx(pHandle, handle, winClass, None)
index -= 1
return handle
def find_subHandle(pHandle, winClassList):
"""
递归寻找子窗口的句柄
pHandle是祖父窗口的句柄
winClassList是各个子窗口的class列表,父辈的list-index小于子辈
"""
assert type(winClassList) == list
if len(winClassList) == 1: # 如果就一层就直接找了
return find_idxSubHandle(pHandle, winClassList[0][0], winClassList[0][1])
else: # 对于多层,递归找下去
pHandle = find_idxSubHandle(pHandle, winClassList[0][0], winClassList[0][1])
return find_subHandle(pHandle, winClassList[1:])
def find_handle_by_wndlist(pHandle, winClassList):
return find_subHandle(pHandle, winClassList)
def select_comboBox_item(PCB_handle, CB_handle, select_index):
if win32api.SendMessage(CB_handle, win32con.CB_SETCURSEL, select_index, 0) == select_index:
win32api.SendMessage(PCB_handle, win32con.WM_COMMAND, win32con.CBN_SELENDOK<<16+0,CB_handle) # 组合框的控制标识符,控件的ID是0,所以低位直接加0
win32api.SendMessage(PCB_handle, win32con.WM_COMMAND, win32con.CBN_SELCHANGE<<16+0, CB_handle) # ID在 spy里找就行
print('改变完成')
else:
raise Exception("Change saving type failed")
CB_SETCURSEL 消息
描述:下拉框操作
参数:
wParam:以0起始的待选选项的索引;如果该值为-1,将从组合框列表中删除当前选项,并使当前选项为空
lParam:未使用。0
返回值:
更改选择成功将返回所设置选项的索引号。
CBN_SELENDOK 通知(notification code)
描述:当用户选择了有效的列表项时发送,提示父窗体处理用户的选择。父窗体通过WM_COMMAND消息接收这个通知。
参数:(作为WM_COMMAND的参数)
wParam:LOWORD为组合框的ID. HIWORD为CBN_SELENDOK的值。
lParam:组合框的句柄。
CBN_SELCHANGE 通知(notification code)
描述:当用户更改了列表项的选择时发送,不论用户是通过鼠标选择或是通过方向键选择都会发送此通知。父窗体通过WM_COMMAND消息接收这个通知。
参数:(作为WM_COMMAND的参数)
wParam:LOWORD为组合框的ID. HIWORD为CBN_SELCHANGE的值。
lParam:组合框的句柄。
也就是说,如果要改变下拉框的选项,要使用这三个消息。
众所周知,,,消息的32位的,而一个消息都有两个参数 ,wparam lparam,当参数不够用时,wparam就分成两半,高字节和低字节,
CBN_SELENDOK notification code
Parameters
wParam
.高字节指定通知代码,低字节就是控件ID(再spy++里找)
lParam
combo box.句柄
所以来个位运算 <<16 左移16位,低位加ID,就行啦
然后就是那个点击的操作,,,win32api.SendMessage(save_win,win32con.WM_COMMAND,win32con.VK_LBUTTON,save_btn_handle)
下面就是WM_COMMAND 参数所有的情况(网页自动翻译的,,可能不准吧)
这应该就是控制操作了,虚拟按键
VK_LBUTTON 0x01
鼠标左键,,,,至于为啥使用 win32api的SendMessage()我也不知道,测试了一下跟win32gui的这个一样的效果。。。。。
文章浏览阅读3.8k次。1、将下载好的萤石js插件,添加到SoringBoot项目中。位置可参考下图所示。(容易出错的地方,在将js插件在html页面引入时,发生路径错误的问题)所以如果对页面中引入js的路径不清楚,可参考下图所示存放路径。2、将ezuikit.js引入到demo-live.html中。(可直接将如下代码复制到你创建的html页面中)<!DOCTYPE html><html lan..._ezuikit 测试的url
文章浏览阅读322次。第二步,在弹出的对话框选择,设备驱动—>PLC—>莫迪康—>ModbusRTU—>COM,根据配置软件选择的协议选期期,这里以此为例,然后点击“下一步”。第四步,把使用虚拟串口打勾(GPRS设备),根据需要选择要生成虚拟口,这里以选择KVCOM1为例,然后点击“下一步”设备ID即Modbus地址(1-255) 使用DTU时,为下485接口上的设备地址。第六步,Modbus的从机地址,与配置软件相同,这里以1为例,点击“下一步“第五步,Modbus的从机地址,与配置软件相同,这里以1为例,点击“下一步“_组态王ua
文章浏览阅读9.4k次,点赞22次,收藏19次。安装npm相当于安装node.js,Node.js已自带npm,安装Node.js时会一起安装,npm的作用就是对Node.js依赖的包进行管理,也可以理解为用来安装/卸载Node.js需要装的东西_npm安装配置
文章浏览阅读748次,点赞21次,收藏26次。大家好,小编来为大家解答以下问题,python基础训练100题,python入门100例题,现在让我们一起来看看吧!宝子们还在新手村练级的时候,不单要吸入基础知识,夯实自己的理论基础,还要去实际操作练练手啊!由于文章篇幅限制,不可能将100道题全部呈现在此除了这些,下面还有我整理好的基础入门学习资料,视频和讲解文案都很齐全,用来入门绝对靠谱,需要的自提。保证100%免费这不,贴心的我爆肝给大家整理了这份今天给大家分享100道Python练习题。大家一定要给我三连啊~
文章浏览阅读1k次。 为了在 Linux ( Ubuntu) 上安装sublime,一般大家都会选择常见的教程或是 sublime 官网教程,然而在国内这种方法可能失效。为此,需要用安装包安装。以下就是使用官网安装包安装的教程。打开 sublime 官网后,点击右上角 download, 或是直接访问点击打开链接,即可看到各个平台上的安装包。选择 Linux 64 位版并下载。下载后,打开终端,进入安装..._ubuntu 安装sumlime text打不开
文章浏览阅读563次,点赞13次,收藏6次。CrossOver24是一款类虚拟机软件,专为macOS和Linux用户设计。它的核心技术是Wine,这是一种在Linux和macOS等非Windows操作系统上运行Windows应用程序的开源软件。通过CrossOver24,用户可以在不购买Windows授权或使用传统虚拟机的情况下,直接在Mac或Linux系统上运行Windows软件和游戏。该软件还提供了丰富的功能,如自动配置、无缝集成和实时传输等,以实现高效的跨平台操作体验。
文章浏览阅读1.7k次。一个用聊天的方式让ChatGPT帮我写的线程安全的环形List_为什么gpt一写list就卡
文章浏览阅读336次。我们在前面的文章里曾写过Web应用中乱码产生的原因和处理方式,旧文回顾:深度揭秘乱码问题背后的原因及解决方式其中我们提到可以通过Filter的方式来设置请求和响应的encoding,来解..._filterconfig selectencoding
文章浏览阅读651次。转自:http://www.jb51.net/article/36480.htmencodeURI和decodeURI是成对来使用的,因为浏览器的地址栏有中文字符的话,可以会出现不可预期的错误,所以可以encodeURI把非英文字符转化为英文编码,decodeURI可以用来把字符还原回来_js encodeur decodeurl
文章浏览阅读1.9w次,点赞6次,收藏3次。前言在日常的Android开发当中,我们肯定要打包apk。但是今天我打包的时候遇到一个很奇怪的问题Android The destination folder does not exist or is not writeable,大意是目标文件夹不存在或不可写。出现问题的原因以及解决办法上面有说报错的中文大意是:目标文件夹不存在或不可写。其实问题就在我们的打包界面当中图中标红的Desti..._the destination folder does not exist or is not writeable
文章浏览阅读94次。一、配置代码编辑区的样式 <1>打开Eclipse,Help —> Install NewSoftware,界面如下: <2>点击add...,按下图所示操作: name:随意填写,Location:http://eclipse-color-th..._ecplise高大上设置
文章浏览阅读2.8k次。一,下载mysql:http://dev.mysql.com/downloads/mysql/; 打开页面之后,在Select Platform:下选择linux Generic,如果没有出现Linux的选项,请换一个浏览器试试。我用的谷歌版本不可以,换一个别的浏览器就行了,如果还是不行,需要换一个翻墙的浏览器。 二,下载完后解压缩并放到安装文件夹下: 1、MySQL-client-5.6.2_linux mysql 安装 mysql-5.6.24-1.linux_glibc2.5.x86_64.rpm-bundle