[Retro 考古] 解秘消失的 Windows Message 0x4

以前开发过 Windows 应用程序的人应该知道一种叫做 Windows Message 的东西。Windows 通过向应用程序窗口传递消息与应用程序窗口通信。消息是一个指定特定事件的数字代码。例如,如果用户按下鼠标左键,窗口将收到一条包含以下消息代码的消息:

#define WM_LBUTTONDOWN    0x0201

为了向窗口传递消息,操作系统调用为该窗口注册的窗口过程(WndProc)。Windows Message 在头文件 WINUSER.H(在 Windows 的最新版本中)或 WINDOWS.H 中定义,下面是其中的一个摘录:

#define WM_NULL                         0x0000
#define WM_CREATE                       0x0001
#define WM_DESTROY                      0x0002
#define WM_MOVE                         0x0003
#define WM_SIZE                         0x0005
#define WM_ACTIVATE                     0x0006
#define WM_SETFOCUS                     0x0007
#define WM_KILLFOCUS                    0x0008

通过幼儿园数学考试的人应该很快意识到一件事 — 没有东西被定义为 0x4。为什么?因为它在很久以前就从 WINUSER.H / WINDOWS.H 中删除了。有人说,一旦有东西被添加到 WINDOWS.H 中,它将永远留在那里,这显然是个例外。又为什么?因为用于发送 Windows Message 0x4 的代码在 Windows 1.0 正式发布之前就被删除了(在 Premiere Edition 和 RTM 之间的某个时间点)。因此,它从未被记录,但它在 WINDOWS.H 中保留了几年(这表明微软非常关心兼容性)。

现在,让我们解开谜团。我们需要先找出神秘的 Windows Message 0x4 的名称。我们知道,此消息是在 Windows 1.0 开发期间添加的,在正式发布 1.01 之前删除的,因此我们应该能够在预发布的 Windows 1.0 版本的 WINDOWS.H 中找到它。Windows 1.0 Alpha Release 是通过传递 Windows Message 与应用程序通信的最早版本,所以让我们看看它的 WINDOWS.H

#define WM_NULL             0x0000
#define WM_CREATE           0x0001
#define WM_DESTROY          0x0002
#define WM_SIZE             0x0003
#define WM_SETVISIBLE       0x0004
#define WM_ENABLE           0x0005
#define WM_SETREDRAW        0x0006
#define WM_SETTEXT          0x0007
#define WM_GETTEXT          0x0008

0x4 似乎是 WM_SETVISIBLE,后来变成了 Windows Message 0x9,这不是我们想要的(它后来也被删除了,但情况不同)。下一个公开发布的版本是 Beta Release,在其 WINDOWS.H 中,我们可以看到:

#define WM_NULL             0x0000
#define WM_CREATE           0x0001
#define WM_DESTROY          0x0002
#define WM_MOVE             0x0003
#define WM_SIZEWAIT         0x0004
#define WM_SIZE             0x0005
#define WM_ACTIVATE         0x0006
#define WM_SETFOCUS         0x0007
#define WM_KILLFOCUS        0x0008

几乎与现代 WINUSER.H 相同,但这次我们看到 WM_SIZEWAIT 被定义为 0x4。由于所有其他内容都相同,因此现在可以安全地将 Windows Message 0x4 称为 WM_SIZEWAIT。由于在 Alpha Release 的 WINDOWS.H 中找不到 WM_SIZEWAIT,我们可以说它是在 Beta Release 中引入的。

如上所述,它从未被记录,因此下一步是找出它的目的并记录下来。要做到这一点,最好的方法是编写一个程序。由于 Beta Release 是最早定义了 WM_SIZEWAIT 的预发布版本,因此最好看看是什么触发了 Windows 在 Beta Release 中发送该消息。

幸运的是,Xelloss 已经为此编写了一个应用程序,所以我们不必编写任何东西。基本上,您需要将 WM_SIZEWAIT 添加到 WndProc 中的 switch 语句中,并在收到它时以某种方式通知您自己。Xelloss 的应用程序在每次收到 WM_SIZEWAIT 时都会发出嘟嘟声,并显示 wParamlParam

Xelloss 的应用程序

由于它的名称很可能与调整大小有关,因此我们需要监视调整应用程序大小时发生的情况。在 Windows 1.0 中调整应用程序的大小时,由于平铺,屏幕上的某些/所有应用程序也必须调整大小。通过执行各种窗口操作,我们可以看到 Windows 将其发送到即将调整大小的窗口,但仅在某些情况下:例如,如果窗口 A 调整了大小,因此另一个窗口 B 的大小必须更改,WM_SIZEWAIT 将发送到 B,而不是 A。基本上,WM_SIZEWAIT 会被发送到将要因为另一个窗口大小调整而被调整大小的窗口。

那么,神秘的 WM_SIZEWAIT 和众所周知的 WM_SIZE 之间有什么区别呢?此表是回答该问题所需的全部内容:

行为WM_SIZEWM_SIZEWAIT
创建此窗口
调整此窗口的大小
最小化此窗口
恢复此窗口
调整另一个窗口的
大小,从而调整此
窗口的大小
将此窗口与另一个
相同大小的窗口交
将此窗口与其他大
小的窗口交换
将另一个相同大小
的窗口与此窗口交
将另一个不同大小
的窗口与此窗口交
WM_SIZEWM_SIZEWAIT

为什么微软要删除它?没人知道。我相信告诉一个窗口它将被因为用户调整了另一个窗口的大小而被调整大小是没有意义的,正如您所看到的,无论如何 WM_SIZE 都将被发送。也许微软删除它是因为它没有用处,也许不是。希望有一天 Raymond Chen 会告诉我们。