5

几年前,我在使用 Visual Basic 时发现了这个MsgBox函数的一个错误。我试图寻找它,但没有人说过任何关于它的事情。但这不仅适用于 Visual Basic。它适用于任何使用标准 Windows MessageBoxAPI 调用的东西。

当标题文本包含多个字符且第一个字符是带有变音符号 ('ÿ') 的小写“y”时会触发该错误。这个角色有什么特别之处?它几乎肯定不是字符本身,而是它的特殊 ASCII 值。'ÿ' 是字符 255 (0xFF),这意味着它是可以存储在无符号字节中的最大值,并且它的所有位都设置为 1。

这个错误有什么作用?好吧,有两种不同的可能性,这取决于标题文本中的字符数。如果标题文本中有偶数个字符(除非是 2),则不会出现消息框,您只会听到警报声。如果标题文本中有两个字符,或者 1 以外的任何奇数(在这种情况下不会触发错误)......然后会发生这种情况:

它在

这还不是全部——消息也将被截断为一行。考虑到此 API 调用的使用频率,这似乎是至少在一个半高调的事件中会发生的错误。互联网上是否有任何关于此的报告,或任何显示可能导致它的原因?也许这是一个与 Unicode 相关的故障,例如记事本中的“灌木隐藏事实”故障?

我制作了一个程序,以防你想玩这个;在这里下载

或者,将以下内容复制到记事本中,使用.vbs扩展名保存,然后双击它以显示上面看到的对话框:

MsgBox "Windows 3.1 font, anyone?", 0, "ÿ ODD NUMBER!"

或者对于不同的字体:

MsgBox "I CAN HAS CHEEZBURGER?", 0, "ÿ HImpact"

编辑:似乎如果前四个字符是ÿ's,即使有奇数个字符,它也不会显示消息。

4

2 回答 2

5

这通常是对话框模板的错误。这不是消息框错误。

例如,在 Visual Studio 中创建默认的 win32 应用程序。在 .rc 文件中,将模板中关于框的标题从

CAPTION "About sampleapp"

CAPTION "ÿT"

当您显示关于框时,该错误将显现出来。

DLGTEMPLATEEX 文档中,请注意菜单和类名具有类型sz_Or_Ord,表示以空字符结尾的字符串或0xFFFF后跟单个单词资源标识符。

Windows 错误地对对话框标题应用了类似的方案:如果第一个字符是,0xFF那么它将标题视为两个 WORD 长,但仅当它试图定位字体信息时。当它显示标题时,它正确地将标题视为字符串。

换句话说,Windows 正在寻找标题字符串中的字体信息。在大多数情况下,这不会指定有效的字体,因此 Windows 默认使用系统字体。

为了证明这一点,我在内存中构建了一个对话框模板(基于此)。一旦这个工作正常,我删除了将字体信息写入模板的代码并使用对话框标题“ÿa\xd\x200\x21SimSun”。这会以斜体 SimSun 显示对话框,因为 Windows 正在从标题字符串中读取字体信息。

这个错误很可能是 16 位 Windows 的遗留问题,其中(我猜)0xFF 被用作资源 ID 标记。

于 2013-10-13T16:36:43.657 回答
3

一个奇怪的错误。我怀疑这些症状是MessageBox()实际显示对话框方式的结果。

在内部,MessageBox() 动态构建对话模板。如果您查看DLGTEMPLATE结构的描述,您会发现以下信息块:

在对话框的标准模板中,DLGTEMPLATE 结构后面总是紧跟三个可变长度数组,它们指定对话框的菜单、类和标题。当指定 DS_SETFONT 样式时,这些数组后面还有一个 16 位值指定点大小和另一个可变长度数组指定字体名称。

因此,对话框模板的内存布局具有紧跟对话框标题的字体规范。

Visual Basic 不使用 Unicode,因此您调用的函数实际上是MessageBoxA(). 这只是一个简单的 thunk,它将传入的字符串从多字节转换为 Unicode,然后调用MessageBoxW().

我相信发生的事情是,出于某种原因,将该字符串从多字节转换为 Unicode 要么出错,要么返回虚假的长度值。当对话框模板在内存中构建时,这会产生连锁反应,即会破坏紧跟在标题字符串之后的内存——正如我们所知,这就是字体规范。

于 2013-10-12T02:44:46.783 回答