代码之家  ›  专栏  ›  技术社区  ›  flarn2006

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

  •  5
  • flarn2006  · 技术社区  · 11 年前

    几年前,我在玩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 回复  |  直到 11 年前
        1
  •  5
  •   arx    11 年前

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

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

    CAPTION "About sampleapp"
    

    CAPTION "ÿT"
    

    当您显示about框时,错误就会显现出来。

    DLGTEMPLATEEX documentation 请注意,菜单和类名具有类型 sz_Or_Ord 这意味着以null结尾的字符串或 0xFFFF 后面跟着一个单词资源标识符。

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

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

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

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

        2
  •  3
  •   Jonathan Potter    11 年前

    一只奇怪的虫子。我怀疑这些症状是 MessageBox() 实际显示对话框。

    在内部, MessageBox()(消息框) builds a dialog template dynamically 。如果你看一下 DLGTEMPLATE 你会发现以下信息:

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

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

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

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