发送消息到窗口或其控件
作者:Rajat
本页讨论 PostMessage 和 SendMessage 命令并将回答这样一些问题:
"如何按下已最小化窗口中的按钮?"
"当 WinMenuSelectItem 不起作用时, 我如何选择一个菜单项?!"
"这是个可更换皮肤的窗口.... 如何确保我每次发送的命令都有效?"
"如果是 隐藏 窗口呢?!"
需要:AutoHotkey v1.0.09+和Winspector Spy (http://www.softpedia.com/get/Security/Security-Related/Winspector.shtml)
像第一个例子那样, 请注意 WinMenuSelectItem 对 Outlook Express 的 "New Message" 窗口中的菜单栏无效. 换句话说, 这代码不起作用:
WinMenuSelectItem, New Message,, &Insert, &Picture...
但 PostMessage 能实现这个操作:
PostMessage, 0x111, 40239, 0, , New Message
太神奇了!但那个是什么? 0x111 是 wm_command 消息 的十六进制代码, 而 40239 是这个特殊窗口理解为选择 'Insert Picture' 菜单项的代码. 现在让我告诉您如何找到类似 40239 这样的值:
- 启动 Winspector Spy, 打开 "New Message" 窗口.
- 拖动 Winspector Spy 窗口中的十字线到 "New Message" 窗口的标题栏 (没有被 Winspector Spy 覆盖的部分).
- 在左边的列表中右键点击所选窗口并选择 'Messages'.
- 右键点击空白窗口并选择 'Edit message filter'.
- 点击 'filter all' 按钮, 然后双击左边列表中的 'wm_command'. 这样您将只监视此消息.
- 现在转到 "New Message" 窗口并在菜单栏中选择: Insert > Picture.
- 返回 Winspector Spy 并按下信号灯按钮来停止监视.
- 展开收集到的 wm_command 消息 (忽略其他的).
- 您想要找的 (通常) 是代码为 0 的消息. 有时会有一些描述为 'win activated' 或 'win destroyed' 以及其他..的 wm_command 消息都是不需要的内容. 您会发现描述为 'Control ID: 40239' 的消息 ...就是它了!
- 现在把它放入上面的命令中您就完成了!它就是 wParam 值.
在下一个例子中我会使用画图程序, 因为很可能每个人都会有. 现在假设我们要使用 AutoHotkey 从工具栏中选择一个工具; 假设要选择取色工具.
您会怎么做? 很可能是使用鼠标点击工具栏, 对吗? 但是按钮可能被移动且隐藏了!这个画图程序的工具栏也可能被移动/隐藏. 所以如果目标用户这么做了, 那么您的脚本在这个点上会失效. 但是下面的命令仍然有效:
PostMessage, 0x111, 639,,,untitled - Paint
PostMessage 的另一个好处是窗口可以在后台; 与之相比, 发送鼠标点击要求目标窗口必须是活动的.
这里有其他的例子. 请注意: 我使用的是 WinXP Pro (SP1) ... 如果您使用不同的操作系统, 那么您的参数可能要改变 (仅适用于像写字板和记事本这类 windows 自带的应用程序; 其他的程序应该不用改变):
;设置写字板字体为青色 PostMessage, 0x111, 32788, 0, , Document - WordPad
;打开记事本的关于对话框 PostMessage, 0x111, 65, 0, , Untitled - Notepad
;切换记事本的自动换行属性 PostMessage, 0x111, 32, 0, , Untitled - Notepad
;在 Windows Media Player 中播放/暂停 PostMessage, 0x111, 32808, 0, , Windows Media Player
;挂起正在运行的 AHK 脚本的热键 DetectHiddenWindows, on SetTitleMatchMode, 2 PostMessage, 0x111, 65305,,, MyScript.ahk - AutoHotkey ; 和挂起操作不同,必须使用 65306 来暂停.
上面讲的是 PostMessage. SendMessage 的工作方式相同, 不过还会等待返回值, 这个值可用于一些情况中, 例如获取 Winamp 中当前正在播放的曲目 (请参阅 自动化 Winamp 的例子).
这里是一些注意事项:
- 上文也提到了操作系统是 XP 且需要注意消息值随着不同的操作系统而改变. 如果您发现一个消息在您的系统上有效 (对于一个软件的某个版本), 那么在其他系统上它对于这个软件的相同版本仍然是有效的. 此外, 大多数应用程序甚至会在它们的不同版本中使用相同的消息值 (例如 Windows Media Player 和 Winamp).
- 如果您已经在 Winspector Spy 中设置了过滤器来只显示 wm_command 消息, 却仍然得到大量的消息时, 请右键点击那些不需要的消息并选择隐藏 (消息名)... 这些消息一般是不是由于您和目标软件交互所产生的消息.
- 在 Winspector Spy 中向右的箭头显示消息值, 而模糊的左箭头显示返回值. 返回值 0 (零) 默认情况下可以安全地认为 '没有错误' (与 SendMessage 一起使用, 返回值会存储在 %ErrorLevel%).
- 要传递消息到匹配部分标题的窗口, 请添加此行到脚本:
SetTitleMatchMode, 2
- 要传递消息到隐藏窗口, 请添加此行到脚本:
DetectHiddenWindows, On
注: 此技术对某些应用程序无效. 我对 VB 和 Delphi 编写的应用程序只能侥幸. 此技术最适用于 C, C++ 编写的应用程序. 对于 VB 应用程序相同命令的 'LParam' 参数在传递时总是变化的. 对于 Delphi 应用程序... 一些程序的 GUI 甚至不使用 wm_command. 它或许使用鼠标位置和点击吧.
去探索吧.... 并且记得在 AutoHotkey 论坛分享您的经验. 欢迎反馈!
这个指南并不是为新手们准备的 (没有冒犯的意思), 因为这些命令被认为是高级功能. 所以如果读完本文,您还是摸不着头脑,请忘了它吧.
-Rajat