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

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

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

    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\0";

问题的确是解决了,但是我觉得微软设计接口也不至于如此弱吧。这样的奇葩的写法不应该是接口设计的规范。于是我研究了下为什么要加\0。
        我们看下
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(\0)结束。假如不是很熟悉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\0*.png\0。
        可以想象下windows对这个串的处理:

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

这个流程就解释了为什么我们需要以两个连续的NULL结尾。

        这儿再多说两句,我们看下mspaint的保存框

这种组合的正确写法是

m_ofn.lpstrFilter =  L"单色位图(*.bmp;*.dib)\0*.bmp;*.dib\0\t16色位图(*.bmp;*.dib)\0*.bmp;*.dib\0\r256色位图(*.bmp;*.dib)\0*.bmp;*.dib\0\r24位位图(*.bmp;*.dib)\0*.bmp;*.dib\0JPEG(*.jpg;*.jpeg;*.jpe;*.jfif)\0*.jpg;*.jpeg;*.jpe;*.jfif\0GIF(*.gif)\0*.gif\0TIFF(*.tif;*.tiff)\0*.tif;*.tiff\0PNG(*.png)\0*.png\0";

解决工作中遇到的一个"打开,保存"文件框的bug的过程的更多相关文章

  1. 15、解决14中csv用excel打开乱码的问题 open('zhihu.csv','w',newline='',encoding='utf-8-sig')

    解决14中csv用excel打开乱码的问题 ,其实就是在写csv的时候把 utf-8 改成 utf-8-sig open('zhihu.csv','w',newline='',encoding='ut ...

  2. vue+webpack项目实际工作中需要生成一个配置文件供生产环境使用

    大家都知道webpack打包十分方便,但是在工作中,前端写好的项目需要后端进行部署,就需要有一个配置文件. 使用插件 :  GenerateAssetPlugin , 使用方法 : 1  在项目中安装 ...

  3. JS 解决 IOS 中拍照图片预览旋转 90度 BUG

    上篇博文[ Js利用Canvas实现图片压缩 ]中做了图片压缩上传,但是在IOS真机测试的时候,发现图片预览的时候自动逆时针旋转了90度.对于这个bug,我完全不知道问题出在哪里,接下来就是面向百度编 ...

  4. 工作中遇到的一个多线程下导致RCW无法释放的问题

    最近有个同事在调用一个类库中的方法时遇到了一个问题,异常信息如下: 尝试释放正在使用的RCW,活动线程或其他线程上正在使用该 RCW,释放正在使用的 RCW 的尝试会导致损坏或数据丢失. 该方法中对w ...

  5. 【技术贴】解决vss中提交pdf下载打开空白乱码

    vss客户端需要安装一个Vss2005的补丁程序,而且之前上传的pdf文件重新删掉,再次上传进Vss中,再下载打卡就ok了. 补丁名称vs80-kb943847-x86-intl.exe 别人的csd ...

  6. 工作中碰到的一个问题(cookie相关)

    今天上线了一个API,6台机器做的集群.API的第一步是读取cookie,判断用户是否登录. 例如,线上服务器分别是 10.255.242.1 10.255.242.2 10.255.242.3 10 ...

  7. css布局 - 工作中常见的两栏布局案例及分析

    突然想到要整理这么一篇平时工作中相当常见但是我们又很忽视的布局的多种处理方法.临时就在我经常浏览的网站上抓的相对应的截图.(以后看到其他类型的我再补充) 既然截了图,咱们就直接看人家使用的布局方式,毕 ...

  8. 博主日常工作中使用的shell脚本分享

    前言: 今天给大家分享一篇在我工作中常用的一个shell脚本,里面有一些我们常用到的shell操作.该脚本用于本地电脑和服务器交互上,实现以下功能: 自动拉取自己个人电脑上的源码到服务器上yocto包 ...

  9. 面试时让你说一个印象最深的bug,该怎么回答

    其实,面试官并不关心你描述的这个bug是否真的有价值,或有多曲折离奇?他只是: * 了解你平时工作中的测试能力 所以,这就要求的你平时工作中遇到bug时试着自己去定位,定位bug的过程远比你的单纯的执 ...

随机推荐

  1. JPA & Hibernate 注解

    1 . @Entity(name="EntityName") 必须 ,name 为可选 , 对应数据库中一的个表 2 . @Table(name="",cata ...

  2. 【gitlab】首次提交本次代码到gitlab上,报错:Updates were rejected because the remote contains work that you do

    首次提交本次代码到gitlab上,报错:Updates were rejected because the remote contains work that you do 报错情况如下: 错误原因: ...

  3. 解决org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource

    spring中做成bean,可以使用property"resourceLoaderPath"指定工程中的路径 <bean id="velocityEngine&qu ...

  4. byte[],bitmap,drawable之间的相互转换

    Byte[]转Bitmap BitmapFactory.decodeByteArray(data, 0, data.length); Bitmap转Byte[] ByteArrayOutputStre ...

  5. Activity间用Intent、Bundle、onActivityResult进行传值

    其实Activity间的传值就是通过Bundle,intent中也是自动生成了Bundle来传值,里面还有个onActivityResult()方法也可以传送数值. 如果一个Activity是由sta ...

  6. 低版本系统兼容的ActionBar(四)添加Tab+添加自定义的Tab视图+Fragment

    在ActionBar中添加Tab是很有用的技巧.在support V7库的支持下,我们几乎可以用和之前一样的方式来添加Tab,对于Tab来说,我们可以和MenuItem一样,给他定义自己的视图.我这里 ...

  7. Java多线程知识-Callable和Future

    Callable和Future出现的原因 创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需 ...

  8. Caffe中deploy.prototxt 和 train_val.prototxt 区别

    之前用deploy.prototxt 还原train_val.prototxt过程中,遇到了坑,所以打算总结一下 本人以熟悉的LeNet网络结构为例子 不同点主要在一前一后,相同点都在中间 train ...

  9. 【google chrome 一键打开 谷歌跳转的页面+JS Replace】谷歌无法打开网页的时候,提取网页中url的部分

    经常在谷歌搜索,遇到网页无法打开,然后就停留在比如:http://www.google.com.hk/search?newwindow=1&safe=strict&site=& ...

  10. Andriod源码搜集

    1.一个左侧抽屉式导航NavigationDraw 教程:http://developer.android.com/training/implementing-navigation/nav-drawe ...