解决工作中遇到的一个"打开,保存"文件框的bug的过程
工作中遇到的这个问题还是很有意思的。其中嵌套了很多奇葩性的问题。 (转载请指明出于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对这个串的处理:
- Search第一个\0,找到“显示字符串”
- 从前一个\0开始搜索第一个\0,寻找到“匹配规则串”
- 从前一个\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的过程的更多相关文章
- 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 ...
- vue+webpack项目实际工作中需要生成一个配置文件供生产环境使用
大家都知道webpack打包十分方便,但是在工作中,前端写好的项目需要后端进行部署,就需要有一个配置文件. 使用插件 : GenerateAssetPlugin , 使用方法 : 1 在项目中安装 ...
- JS 解决 IOS 中拍照图片预览旋转 90度 BUG
上篇博文[ Js利用Canvas实现图片压缩 ]中做了图片压缩上传,但是在IOS真机测试的时候,发现图片预览的时候自动逆时针旋转了90度.对于这个bug,我完全不知道问题出在哪里,接下来就是面向百度编 ...
- 工作中遇到的一个多线程下导致RCW无法释放的问题
最近有个同事在调用一个类库中的方法时遇到了一个问题,异常信息如下: 尝试释放正在使用的RCW,活动线程或其他线程上正在使用该 RCW,释放正在使用的 RCW 的尝试会导致损坏或数据丢失. 该方法中对w ...
- 【技术贴】解决vss中提交pdf下载打开空白乱码
vss客户端需要安装一个Vss2005的补丁程序,而且之前上传的pdf文件重新删掉,再次上传进Vss中,再下载打卡就ok了. 补丁名称vs80-kb943847-x86-intl.exe 别人的csd ...
- 工作中碰到的一个问题(cookie相关)
今天上线了一个API,6台机器做的集群.API的第一步是读取cookie,判断用户是否登录. 例如,线上服务器分别是 10.255.242.1 10.255.242.2 10.255.242.3 10 ...
- css布局 - 工作中常见的两栏布局案例及分析
突然想到要整理这么一篇平时工作中相当常见但是我们又很忽视的布局的多种处理方法.临时就在我经常浏览的网站上抓的相对应的截图.(以后看到其他类型的我再补充) 既然截了图,咱们就直接看人家使用的布局方式,毕 ...
- 博主日常工作中使用的shell脚本分享
前言: 今天给大家分享一篇在我工作中常用的一个shell脚本,里面有一些我们常用到的shell操作.该脚本用于本地电脑和服务器交互上,实现以下功能: 自动拉取自己个人电脑上的源码到服务器上yocto包 ...
- 面试时让你说一个印象最深的bug,该怎么回答
其实,面试官并不关心你描述的这个bug是否真的有价值,或有多曲折离奇?他只是: * 了解你平时工作中的测试能力 所以,这就要求的你平时工作中遇到bug时试着自己去定位,定位bug的过程远比你的单纯的执 ...
随机推荐
- android模拟器修改时间
我们看右上角的模拟器的时间,是不是和我们现在时间不同步呢 点击主菜单之后,我们找到下边的设置的按钮 下边找到时间和日期, 怎么把页面修改中文, 可以看(安卓模拟器怎么修改语言)的经验 ...
- SurfaceFlinger( 226): Permission Denial: can't access SurfaceFlinger
MODIFY_PHONE_STATE permission is granted to system apps only. For your information, there are 2 type ...
- python测试开发django-43.session机制(登录/注销)
前言 当我们登录访问一个网站时,服务器需要识别到你已经登录了,才有相应的权限访问登录之后的页面.用户退出登录后,将无权限访问再访问登录后的页面. 从登录到退出的一整个流程,可以看成是与服务器的一次会话 ...
- java反射遍历实体类属性和类型,并赋值和获取值
/* * GetModelNameAndType.java * Version 1.0.0 * Created on 2017年12月15日 * Copyright ReYo.Cn */ packag ...
- SeekBar的用法和自定义滑块的样式
SeekBar继承自ProgressBar,所以基本一样,我们自定义一般也就是顶一个滑块的图片而已. 布局文件 <RelativeLayout xmlns:android="http: ...
- C# 访问操作注册表整理
一..net注册表操作简介 .net中Registry 类,RegistryKey 类提供了操作注册表的接口 RegistryValueKind,用于指定操作注册表的数据类型. 二.使用实例 //获取 ...
- 连接sqlServer数据库&jpa调用存储过程Java获取存储过程返回的多个结果集JAVA调用sqlserver存储过程的实现(返回多个结果集的实现)jdbc多结果集(getMoreResults)
存储过程: BEGIN select * from teacher; SELECT * FROM student; END public Object GetMyBOProjectProductLis ...
- android自己定义换行居中CenterTextView
在我们开发app时,TextView一定是使用最多的控件了,android自带的TextView的功能也十分强大.但还是有些小的地方不能满足我们的需求.几天要说的这个功能也是开发中非经常见的.就是,在 ...
- 描述ARP协议的工作原理,怎么实施ARP攻击和防御ARP攻击
什么是ARP协议?ARP,即地址解析协议,实现通过IP地址得知其物理地址.在TCP/IP网络环境下,每个主机都分配了一个32位的IP地址,这种互联网地址是在网际范围标识主机的一种逻辑地址.为了让报文在 ...
- cplusplus 库 在线管理; 类似于 python的 pip install 、nodejs 的npm模块
cplusplus 库 在线管理: 类似于 python的 pip install .nodejs 的npm模块 还有 apache 经常使用的 Apache Ivy 项目依赖管理工具/Maven 这 ...