几年前,我正在用Visual Basic搞乱,并且发现了MsgBox
函数的一个bug。 我试图寻找它,但没有人曾经说过。 不仅仅是用Visual Basic, 它与任何使用标准Windows MessageBox
API调用的东西都是一样的。
当标题文本有多个字符时,触发该错误,并且第一个字符是带变音符('ÿ')的小写'y'。 这个angular色有什么特别之处? 它几乎肯定不是字符本身,而是它的ASCII值是特殊的。 'ÿ'是字符255(0xFF),表示它是可存储在无符号字节中的最高值,其所有位都设置为1。
这个bug有什么作用? 那么,有两种不同的可能性,这取决于标题文本中的字符数量。 如果在标题文本中有偶数个字符(除非是2),则不会出现消息框,您只会听到警报声。 如果标题文本中有两个字符,或者是除1以外的任何奇数(在这种情况下,错误不会被触发),则会发生这种情况:
而这还不是全部 – 消息也将被截断为一行。 这似乎是至less在一个半高调事件中会发生的一种错误,考虑使用这个API调用的频率。 有没有在互联网上的任何报告,或任何显示可能导致它的事情? 也许这是一个Unicode相关的故障,就像记事本中的“布什隐藏事实”毛刺一样?
我做了一个程序,以防你想玩这个; 在这里下载 。
或者,将以下内容复制到记事本中,将其保存为.vbs
扩展名,然后双击以显示上面显示的对话框:
MsgBox "Windows 3.1 font, anyone?", 0, "ÿ ODD NUMBER!"
或者为不同的字体:
MsgBox "I CAN HAS CHEEZBURGER?", 0, "ÿ HImpact"
编辑:看来,如果前四个字符是ÿ
的,它不会显示该消息,即使有一个奇数字符。
一个奇怪的错误。 我怀疑这些症状是MessageBox()
实际显示对话框的结果。
在内部, MessageBox()
动态地构建一个对话框模板 。 如果你看一下DLGTEMPLATE
结构的描述,你会发现下面的信息块:
在对话框的标准模板中,DLGTEMPLATE结构总是紧跟着三个可变长度数组,这些数组指定对话框的菜单,类和标题。 当指定了DS_SETFONT样式时,这些数组后面跟着一个指定点大小的16位值和一个指定字体名称的另一个可变长度数组。
因此,对话框模板的内存中布局的对话框标题后紧跟着字体指定。
Visual Basic不使用Unicode,因此您调用的函数实际上是MessageBoxA()
。 这只是一个thunk,它将传入的字符串从多字节转换为Unicode,然后调用MessageBoxW()
。
我相信发生了什么,出于某种原因,该字符串从多字节到Unicode的转换要么是错误的,要么返回一个虚假的长度值。 这在对话框模板被建立在内存中时具有连锁效应,即在标题字符串之后立即破坏存储器 – 正如我们所知的那样,是字体规格。
这是一个对话框模板的错误。 这不是一个消息框错误。
例如,在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标记。