有没有人听说过标准Windows消息框的这个奇怪的错误?

时间:2013-10-12 01:14:08

标签: windows winapi fonts messagebox

多年前,我正在使用Visual Basic,我发现了MsgBox函数的错误。我试着寻找它,但没有人曾经说过这件事。它不仅仅是Visual Basic;它与使用标准Windows MessageBox API调用的任何内容一起使用。

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

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

It's in the "System" font (as used in Windows 3.1.)

并非全部 - 消息也将被截断为一行。考虑到使用此API调用的频率,这似乎是至少在一个半高调事件中会发生的那种错误。互联网上有没有这方面的报道,或者有什么可能导致它的原因?也许这是一个与Unicode相关的故障,就像记事本中的“布什隐藏事实”故障一样?

我做了一个程序,以防你想玩这个; download it here

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

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

或者换一种不同的字体:

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

编辑:似乎如果第一个四个字符是ÿ的,它就不会显示消息,即使有一个奇怪的字符数。

2 个答案:

答案 0 :(得分:5)

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

例如,在Visual Studio中创建默认的win32应用程序。在.rc文件中,从

更改about框的模板中的标题
CAPTION "About sampleapp"

CAPTION "ÿT"

当您显示about框时,错误将自动显示。

DLGTEMPLATEEX documentation注意,菜单和类名称的类型为sz_Or_Ord,这意味着以空字符结尾的字符串或0xFFFF后跟单个字资源标识符。

Windows错误地将相似的方案应用于对话框标题:如果第一个字符是0xFF,则它将标题视为两个WORD长,但仅在它尝试查找字体信息时。当它显示标题时,它会正确地将标题视为字符串。

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

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

这个bug可能是16位Windows的宿醉,其中(我猜)0xFF被用作资源ID标记。

答案 1 :(得分:3)

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

内部MessageBox() builds a dialog template dynamically。如果你看一下DLGTEMPLATE结构的描述,你会发现以下信息:

  

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

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

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

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