# 向窗口或者窗口控件发送消息，作者：Rajat

本页讨论 PostMessage 和 SendMessage 命令，并将回答这样一些问题：

“我如何按下已被最小化的窗口中的按钮？”
“当 WinMenuSelectItem 不起作用时，我如何选中一个菜单项？！”
“这是个可更换皮肤的窗口……如何保证我发送的命令每次都能生效？”
“隐藏窗口的话该怎么办？！”
环境要求：AutoHotkey v1.0.09+ 以及 Winspector Spy (www.windows-spy.com)

例如第一个例子中，注意 WinMenuSelectItem 命令就对 Outlook Express 的"New Message"窗口上的菜单栏无效。换言之，该代码不起任何作用：

WinMenuSelectItem, New Message,, &Insert, &Picture...

但 PostMessage 命令就能完成这个工作：

PostMessage, 0x111, 40239, 0, , New Message

好神奇啊！但那是啥鬼东西？0x111 是 wm_command 消息 的十六进制代码，40239 是让这个特殊的窗口理解为选择 'Insert Picture' 菜单项的代码。现在让我来告诉你如何获得一个类似 40239 这样的值：

1. 启动 Winspector Spy 软件，打开 "New Message" 窗口。
2. 拖动 Winspector Spy 窗口中的十字光标到 "New Message" 窗口的标题栏上(未被 Winspector Spy 窗口的覆盖效果遮蔽的部分)。
3. 在左边列表中被选中的窗口名称上点击右键，选择 'Messages'。
4. 右键点击空白窗口并选择 'Edit message filter'。
5. 按 'filter all' 按钮，然后双击左边列表中的 'wm_command' 项。这样你将只监视此消息。
6. 现在转到 "New Message" 窗口并从菜单栏选择:Insert > Picture 。
7. 返回 Winspector Spy 并按下信号灯按钮来暂停监视。
8. 展开收集到的 wm_command 消息(忽略其它消息)。
9. 你想要找的(通常)是一个代码为 0 的消息。有时那里描述为 'win activated' 或者 'win destroyed' 以及其它等等……都是不需要的内容。你要是发现那有一个描述为 'Control ID: 40239' 的消息……那就是它了！
10. 现在将它放入上面的命令中你就搞定了！它就是 wParam 参数的值。

在下一个例子中，我会用到画图，因为大概每个人都会有。现在，让我们假设你要使用 AutoHotkey 从一个程序的工具栏选择一个工具；假设选择的就是取色这个工具。

你会怎么做？很可能是在工具栏按钮上用鼠标点击，对吧？但是工具栏可以被移动或者隐藏！在画图中也可以。所以如果目标用户移动或隐藏了工具栏，那么你的脚本在那个点上将会失效。但是下面的命令仍将有效：

PostMessage, 0x111, 639,,,未命名 - 画图

PostMessage 的另一个好处是窗口可以处在后台；相比之下，发送鼠标击键需要窗口处于激活状态。
下面有更多的例子。注意：我用的是 WinXP Pro (SP1)……如果你使用的是不同的操作系统，那可能需要调整下参数(仅对于像写字板和记事本这种 windows 自带的应用程序；其它的程序而言参数应该不用改变)。

;写字板字体设为青色
PostMessage, 0x111, 32788, 0, ,文档 - 写字板

;在记事本打开关于对话框
PostMessage, 0x111, 65, 0, ,无标题 - 记事本

;在记事本切换自动换行
PostMessage, 0x111, 32, 0, ,无标题 - 记事本

;播放/暂停 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 中当前播放的曲目(请看 Automating Winamp 里的例子)。

这里还有些注意事项：

- 上文也提到了操作系统是 XP 并且要谨记消息值随着不同的操作系统而改变。如果你发现一个消息可以在你的系统上使用(对一个软件的某个版本)，那么它肯定也能用同样版本的软件在其它系统上使用。此外，大多数应用程序即使在不同的版本中也保持相同的消息值(例如 Windows Media Player 和 Winamp)。
- 如果你已在 Winspector Spy 设置了过滤仅显示 wm_command 消息，而你仍然获得大量的消息,这时，在那消息上点右键选择 hide (消息名称)……你不会想要看到那个不是你与目标软件交互而出现的消息。
- 在 Winspector Spy 中向右的箭头显示消息值，模糊的向左的箭头显示返回值。返回值为 0，可默认安全地视为 'no error'(使用 SendMessage 命令，返回值将会在 %ErrorLevel% 中)。
- 要给部分标题匹配的窗口传递消息，在脚本里加上这行：
  SetTitleMatchMode, 2
- 要给隐藏窗口传递消息，在脚本里加上这行：
  DetectHiddenWindows, On

注意：此技术对某些应用程序无效。我对 VB 和 Delphi 编写的应用程序用时只能侥幸。此技术最适于 C, C++ 编写的应用程序。对于 VB应用程序，同个命令的 'LParam' 参数在传递时总是变化。对于 Delphi 应用程序……一些程序的GUI (用户图形界面)甚至不使用 wm_command 。它大概使用了鼠标位置和点击。

去探索吧……要在 AutoHotkey 论坛分享你的经验哦。欢迎您反馈信息！

这个指南并不是为新手们准备的(没有冒犯的意思)，因为这些命令被认为是高级专题。所以如果读完本文，你还是摸不着头脑的话，请忘了它吧。

-Rajat

翻译：lwjiee 修正：天堂之门 menk33@163.com 2008年8月24日