zoukankan      html  css  js  c++  java
  • 解决工作中遇到的一个"打开,保存"文件框的bug的过程

            工作中遇到的这个问题还是很有意思的。其中嵌套了很多奇葩性的问题。 (转载请指明出于breaksoftware的csdn博客)

            我们来看下故事的发生过程,QA同学发现我们存在如下的bug


            看到如此多的串,可以认为这个是典型的溢出问题。后来我咨询解决该问题的同学,他说这个bug在debug模式下不会出现,只有在release下才会出现(这个意味着,该问题很有可能是内存问题引起的,因为debug和release的一个很大的区别就是内存初始化和布局)。解决方案就是在筛选器后面加个。

        OPENFILENAME m_ofn;
        ::ZeroMemory(&m_ofn, sizeof(m_ofn));
        m_ofn.lStructSize = sizeof(m_ofn);
        m_ofn.hwndOwner = m_hwnd;
        m_ofn.lpstrFilter =  L"png|*.png";
    

            问题的确是解决了,但是我觉得微软设计接口也不至于如此弱吧。这样的奇葩的写法不应该是接口设计的规范。于是我研究了下为什么要加。
            我们看下 http://msdn.microsoft.com/en-us/library/ms646839(VS.85).aspx,它记录了OPENFILENAME结构体的说明,其中对lpstrFilter的说明有如下内容

    lpstrFilter
    Type: LPCTSTR
    A buffer containing pairs of null-terminated filter strings. The last string in the buffer must be terminated by two NULL characters.

            其中特别说明了,这个串的最后要以两个NULL()结束。假如不是很熟悉windows设计的同学,可能此时已经感叹微软真的有这样奇葩的设计了。
            但是,真实的问题却是我们没有关注到的:这样的写Filter是正确的么?(需要转换下思维了)通过Filter这个名字,我们可以猜想到,这个是选择器,让我们的文件“打开,保存”框只筛选出符合我们规则的文件。我们看下画板程序的文件打开框的选择

            此时我们选择的是jpeg格式,则显示了所有后缀为jpg的文件。如果我们选择png格式,则只显示后缀为png的文件。如下图


            而用我们的代码打开的是


            这可以见得,我们的筛选器失效了。这也意味着,我们的筛选器写法是有问题。找到这个问题,就离我们找到为什么lpstrFilter要以两个NULL结尾的问题不远了。
            其实我们仔细看下MSDN的说明。可以知道lpstrFilter保存的是若干个“字符串对”(A buffer containing pairs of null-terminated filter strings.)。这种设计思想,在windows上很多的,比如可以看http://blog.csdn.net/breaksoftware/article/details/3914358这篇文章中介绍的PendingFileRenameOperations注册表项,其记录的数据也是若干个“字符串对”。lpstrFilter中的每个“字符串对”,第一个字符串保存的是用于在框的“保存类型”中显示的文字,比如png;二个字符串保存的是“筛选规则”(不会显示出来,供窗口筛选用),比如*.png。而我们的窗口中显示的是png|*.png。此时似乎我们懂了点什么……这个就是我们写错了!我猜测这段代码的作者,也是希望做成有筛选功能的,否则也不用指定这个字段。但是他可能认为“|”是分隔符。于是便有了
                png                |             *.png
          (显示名)  (分隔符)  (筛选器)
            话说


            这样的显示也忒不协调了!
            正确的写法是png*.png。
            可以想象下windows对这个串的处理:

    1. Search第一个,找到“显示字符串”
    2.  从前一个开始搜索第一个,寻找到“匹配规则串”
    3.  从前一个开始搜索第一个,如果位置和前一个不相邻,则走到1;否则结束搜索

            这个流程就解释了为什么我们需要以两个连续的NULL结尾。
            这儿再多说两句,我们看下mspaint的保存框


            这种组合的正确写法是

    m_ofn.lpstrFilter =  L"单色位图(*.bmp;*.dib)*.bmp;*.dib	16色位图(*.bmp;*.dib)*.bmp;*.dib
    256色位图(*.bmp;*.dib)*.bmp;*.dib
    24位位图(*.bmp;*.dib)*.bmp;*.dibJPEG(*.jpg;*.jpeg;*.jpe;*.jfif)*.jpg;*.jpeg;*.jpe;*.jfifGIF(*.gif)*.gifTIFF(*.tif;*.tiff)*.tif;*.tiffPNG(*.png)*.png";
  • 相关阅读:
    调度器2—cat /proc/<pid>/sched内容分析
    调度器1—相关接口和命令行工具
    Java中的String类
    Java中的数组
    代码访问使用Let's Encrypt证书的网站提示certificate has expired的解决方法
    Linux环境Clion使用Protobuf
    PyTorch Dataloader读取时如何在进程之间传输数据
    6 安装Grafana 展示promethues数据
    5 Prometheus relabel配置
    4 PromQL
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3402538.html
Copyright © 2011-2022 走看看