在调试应用程序以尝试提高性能时,我发现它在处理大于 0xC000 的消息时浪费了时间。这显然是由
RegisterWindowMessage
API 创建的消息。然而,该应用程序使用了超过两百个这样的消息;有没有办法通过数值找到消息的原始名称?
GetAtomName
和 GlobalGetAtomName
失败并显示
错误_无效_句柄
错误。
话虽这么说,
RegisterWindowMessage()
和RegisterClipboardFormat()
碰巧当前共享单个原子表(以及一些其他API函数),因此在当前版本的Windows中,您可以使用GetClipboardFormatName()
来获取已注册的窗口消息的名称。
Raymond Chen 在 MSDN 上的博客对此进行了描述:
如何调查大量泄漏窗口类(RegisterClass)的可能性?
其他一些地方出现了原子(以及神奇的 0xC000)我将从 RegisterWindowMessage 函数创建的已注册窗口消息开始。恰好在当前版本的 Windows 中,注册的类名、注册的剪贴板格式名称和注册的窗口消息名称都来自同一个原子表。我想重申,这是一个可以随时更改的“实现细节”,因此不要对此有任何依赖。我提供此信息用于诊断目的,这就是我们这里所拥有的。 客户遇到问题可以这样做:
Foreach atom in (0xC000 .. 0xFFFF) If (GetClipboardFormatName(atom, buffer, bufferSize)) Print buffer
这将打印出所有类的名称、剪贴板格式和注册的窗口消息。原子表中有 16,384 个原子的空间,而实际上不会超过一百个左右,所以如果你看到超过 15,000 个条目,这是一个非常好的迹象,表明你正在泄漏类。
这些不是正式的原子没有官方 API;它们只是恰好位于 0xC000 到 0xFFFF 范围内的整数,就像原子一样。但是,是的,在内部,它们是原子。当然,您不应该依赖它,因为它不是合同性的。认为这是一个奇妙的巧合。 由 RegisterClipboardFormat 消息创建的注册剪贴板格式也
不是正式的原子;它们只是 UINT。注册剪贴板格式的数字范围甚至没有指定;它们在 0xC000 范围内徘徊只是一个实现细节。有一天,注册的剪贴板格式可能会有像 0x1234 这样的值,谁知道呢。
因此,正如我所说,目前
可以获取已注册窗口消息的名称,但您可以当前通过将已注册窗口消息与已注册剪贴板格式视为相同来解决此问题。但是,如果 GetClipboardFormatName()
的实现发生变化,以这种方式使用
RegisterWindowMessage()
可能会在未来中断。