今天得空,正好把我前阵子捣鼓那个 `profilestring` 相关的东西记录一下,省得以后忘。
起因
事情是这样的,我手头有个小程序,需要存点配置信息,比如窗口上次的位置,用户的一些选项之类的。一开始想得挺复杂,什么注册表、数据库都过一遍脑子,后来觉得太麻烦,就这点儿东西,用个 ini 配置文件最省事。简单、直观,记事本都能打开改。
开始动手
说干就干。我就想起来 Windows 不是有现成的函数嘛专门读写 ini 文件的,好像叫什么 `WritePrivateProfileString` 和 `GetPrivateProfileString`。凭着模糊的记忆,我就开始动手。
先是写配置。这个 `WritePrivateProfileString` 函数,用起来感觉还行。你看,它要几个东西:
- 文件名: 就是你的 ini 文件叫放哪儿。
- 节名(Section): 就是 ini 文件里那个方括号括起来的名字,比如 `[Settings]`。
- 键名(Key): 就是你要存的具体配置项的名字,比如 `WindowWidth`。
- 要写入的值: 这个就是要保存的数据,比如 `800`。
我就照着这个思路,把程序里需要保存的几个变量,一个个调用这个函数给写进去。写完之后,我特意打开那个 ini 文件瞅瞅,数据确实都在里面,格式也对,心里还挺得意的。
遇到麻烦
得意不能太早。 接着我就开始写读取配置的代码,用的是 `GetPrivateProfileString`。这个函数也差不多,提供文件名、节名、键名,然后它把读到的值给你返回来。
麻烦来。我第一次运行读取配置的代码,读出来的值是空的,或者有时候是乱码!我当时就懵,明明刚才看文件里写得好好的,怎么读出来就不对?
我反反复复检查代码,文件名、节名、键名都对得上,大小写也看过,没问题。然后我试着直接在 ini 文件里手动改几个值,再去读,结果还是不对。有时候能读到,有时候又不行,特别是当我保存的值里面有中文的时候,乱码问题更严重。
我还碰到一个怪事,就是那个 `GetPrivateProfileString` 函数有时候会返回一个错误码,好像是 2,提示说找不到文件。可文件明明就在那儿放着!真是奇怪。
排查过程
没办法,只能硬着头皮查。我先是怀疑路径问题,把相对路径改成绝对路径试试,不行。又怀疑是不是权限问题,也没发现什么异常。
后来我就琢磨,是不是编码搞错?因为我注意到,用 `WritePrivateProfileString` 写进去之后,如果我用记事本打开再保存一下,有时候读取就出问题。我就想起来,Windows 记事本保存文件的时候,可以选编码格式,比如 ANSI、UTF-8、Unicode 什么的。
然后我去看我当时那个项目的设置,发现默认用的是 Unicode 字符集。我就猜,是不是 `WritePrivateProfileString` 和 `GetPrivateProfileString` 这俩函数,在处理 Unicode 和 ANSI 编码的时候有点讲究?或者说,我项目设置和函数默认行为不匹配?
网上搜搜(不是直接用网上的代码,主要是看思路),果然很多人提到这个问题。有人说,如果你项目是 Unicode 的,那直接用 `WritePrivateProfileString` 和 `GetPrivateProfileString` 可能默认处理的是 ANSI,或者反过来,反正就是不匹配导致乱码或者读取失败。
找到办法
找到问题就好办。 我试几种方法:
- 一种是,有人说可以直接调用带 A 后缀的函数,比如 `WritePrivateProfileStringA` 和 `GetPrivateProfileStringA`,强制使用 ANSI 编码来读写。我试下,对于纯英文和数字的配置,好像是好使。
- 另一种是,修改项目的字符集设置。我把项目的“字符集”设置从“使用 Unicode 字符集”改成“未设置”或者“使用多字节字符集”。这一招效果最明显! 改完之后,重新编译运行,不管是写入还是读取,中文英文数字都正常,也没再出现那个找不到文件的错误提示。
看来主要就是这个编码设置在捣鬼。可能是我创建项目时用默认的 Unicode 设置,但这两个老的读写 ini 文件的函数,在某些情况下对 Unicode 支持得不是那么“智能”,或者说需要更严格的对应。改成多字节(很多时候就是 ANSI)之后,就匹配上。
结果
最终,通过调整项目的字符集设置,我那个用 `profilestring` 函数读写 ini 配置文件的小功能总算是跑顺畅。配置能正确保存,程序启动时也能正确加载,中文也没问题。
虽然过程有点波折,但也算搞明白这里面的一个坑。这经验记下来,以后再用这俩函数,就知道得先注意检查项目字符集设置和函数行为是不是匹配。省得再掉进同一个坑里。