zoukankan      html  css  js  c++  java
  • 记一次曲折的多资源文件拆分折腾过程(1)

    记一次曲折的多资源文件拆分折腾过程(1)

    缘起

    最近这些天,我一有时间就捣鼓 .rc 。用 git 管理过 .rc 文件的小伙伴儿应该都知道,.rc 文件会被 git 默认当作二进制文件来管理。每次合并代码的时候,只要涉及到 .rc 文件的变更,很大概率会报冲突,而且工具不能很好的解决,只能手动解决。为了解决这个问题,我想到了两个方案:

    1. git.rc 文件当成普通文件来管理。
    2. 把一个大的 .rc 文件拆成多个小的 .rc 文件,这样可以有效的降低冲突的概率。

    这两个方案相互之间没有任何冲突,所以这次折腾的时候,这两个方案是同时进行的。本以为没什么值得写的,没想到收获了意外惊喜,于是有了本篇总结。

    拆分 rc

    按照微软官方文档 TN035: Using Multiple Resource Files and Header Files with Visual C++ 的指示,很快就拆分好了。满心欢喜的准备编译运行,验收成果。

    没想到……

    初遇错误

    编译很快结束了,不过 vs 报告了下图所示的编译错误:

    unexpected-end-of-file-error
    unexpected-end-of-file-error

    乍一看有一点懵,不过仔细看文件内容后知道怎么回事了。原来这是一个“老朋友”了,之前遇到过。不是什么大问题,只需要在后面多加一个空行就行了。

    温馨提示:

    如果在 resource.h 中包含自定义的头文件时,也需要在被包含的头文件的末尾加一个空行。否则也会报错。

    在末尾加好空行后,再次编译,成功,正常运行。

    multiple-rc-include-success
    multiple-rc-include-success

    解决了在同一工程中使用多个 .rc 的问题,下一个问题是让 git 不再把 .rc 文件当成二进制文件来管理。默认情况下,.rc 文件会被当成 binary file 来管理的,当 .rc 中有差异的时候,在命令行中执行 git diff 命令,不能显示出有意义的信息。

    binary-rc-diff-fail
    binary-rc-diff-fail

    修改 git 设置

    按照 gitattribtes帮助文档 中的说明,我在项目根目录建立了 .gitattributes 文件,把 .rc.rc2 文件都当成 UTF-16 来管理,这样再冲突的时候就可以比较差异了。

    gitattributes
    gitattributes

    说明:

    因为现有项目中的 .rc 文件都被当成了二进制文件,所以我在 .gitattributes 中末尾的位置把旧的 .rc.rc2 文件强制设置为了 binary

    设置好 .gitattributes 文件后,手动修改 .rc 文件内容,然后执行 git diff 查看差异。结果如下图,这次显示的差异简直完美。以说明新增加的设置是生效的。

    git-diff-rc-success
    git-diff-rc-success

    本以为本次折腾就这么顺利的结束了,可以打扫战场,编写操作文档,收工了。

    没想到……

    高兴的太早了

    撤销完变更后,编译,居然出现了下图中的错误:

    error-RC1020-unexpected-endif
    error-RC1020-unexpected-endif

    这是什么错误?一脸懵逼,难道上面哪个地方多写了 #endif 导致不匹配了?赶紧把改动过的文件都检查一遍,尤其是刚刚改动过的文件。

    check-file-modification
    check-file-modification

    每个文件都反反复复看了好几遍,什么问题都没看出来。#if#endif 都是成对儿的。这可如何是好,网上搜索 error RC1020,没有一条能解决我遇到的问题。

    绝望

    看了很长时间也没发现哪不对,于是我开始玄学了。

    • 难道是在 .rc 中不能加重复包含的保护?不应该啊,在其它地方看到过类似的用法,还特意模仿着写的。不管三七二十一了,删除,编译,依然报错。

    • 难道 #include 的头文件路径不对?调整包含路径,依然报错。

    • 难道不能在 .rc 中包含头文件?不应该啊,默认生成的 .rc 就包含了 resource.h 啊。删除,可想而知,依然报错。

    • 难道……

    就这样排除了很多种“可能性”,试了很多方案,都没有用。但是得到了一个结论:只要包含这个 .rc 文件,编译就有问题。要不是刚开始在拆分完 .rc 后已经成功运行程序了,我都有些怀疑是不是不支持在同一个工程中使用多个 .rc了。

    柳暗花明

    实在不知道是哪里出问题了,于是起来接了杯水,在回座位的路上,脑子里突然蹦出来一个想法:双击打开有问题的 .rc 文件看看能不能看出点什么门道来。如下图:

    open-rc-by-double-click
    open-rc-by-double-click

    嗯?怎么是空的?我的对话框去哪了?(内心一阵窃喜)赶紧打开一个正常的 .rc 文件看看,如下图:

    open-normal-rc-by-double-click
    open-normal-rc-by-double-click

    该有的都有。手动把正常显示的对话框的内容拷贝到有问题的 .rc 中,看看能否打开,发现居然还是打不开!!!炸了,赶紧通过 beyond compare 对比看看。

    compare-two-rc-files
    compare-two-rc-files

    虽然提示 Difference not found,但是如果仔细看的话,两边的编码是不同的。为了进一步确认,于是打开 Hex Editor 查看文件头,果然不一样。hex-compare-bom-header

    正常的 .rc 文件是按小端存储的—— FF FE,也就是UTF16 LE with Bom。有问题的 .rc 文件是按大端存储的—— FE FF,也就是 UTF16 BE With Bom

    知道了原因,于是赶紧修改有问题的 .rc 文件为小端模式.

    警告:

    不能直接修改文件头,否则打开时文件内容不对。可以使用 notepad.exe 打开有问题的 .rc 文件,然后另存为的时候选 UTF16 LE 即可。

    save-as-utf16-le

    再次双击打开发现可以正常打开了,并且编译也没问题了。特地贴一张编译通过的截图,我太难了。

    compile-success
    compile-success

    又遇错误

    本以为编译都通过了,应该就万事大吉了吧,没想到运行的时候直接崩溃了。我也要崩溃了。

    startup-fail
    startup-fail

    说明:
    因为我设置了 windbgJIT 调试器,所以程序崩溃后直接到 windbg 中了。

    vs 中按 F10 启动,单步跟踪,很快就发现是获取对话框的时候失败了。

    debug-startup-fail
    debug-startup-fail

    看来又是 .rc 问题,难道生成的程序的资源段有问题了?使用 CFF Explorer 打开程序查看资源段,如下图:

    view-pe-resource-segment
    view-pe-resource-segment

    果然,程序资源段中没有任何对话框,难怪查找对话框的时候找不到。看来跟刚才的 .rc 是一个问题,查看对应的 .rc 文件的文件编码,果然是一样的问题。修改文件编码,然后重新生成,启动后终于正常了。

    总结

    这次的折腾真是一波三折,有点意思。几个关键点总结如下:

    • 如果想在 resource.h#include 自定义的头文件,务必确保自定义头文件结尾多留一个空行,同样的道理,如果一个 .rc 文件包含在另外一个 .rc 文件中,也务必在结尾多留一个空行。
    • .rc 文件要求是UTF-16 LE With Bom 格式的,一定不能搞错。 p.s. 在查资料过程中,发现也可以指定为 UTF8 格式,但是我没成功。
    • CFF Explorer 真的是查看 PE 的好帮手,你值得拥有。
    • 程序是最讲道理的,对就是对,不对就是不对。遇到诡异问题,一定不能迷信,也不能瞎猜。

    参考资料

    未完待续

    虽然问题解决了,但是为什么 .rc 文件的编码变了?而且还变错了。会是 gitbug 吗?

    敬请期待后续文章……

    欢迎各位小伙伴指出不足,提出建议!感谢关注我的博客:)
  • 相关阅读:
    windows关闭aslr办法
    linux关闭地址空间随机化(ASLR)
    Hadoop 2.7.2 集群搭建(转载)
    ssh免密码登录
    二、hadoop文件操作
    一、hadoop安装与配置
    转载model操作
    python实现线程池
    自定义django admin及其界面
    django管理界面使用与bootstrap模板使用
  • 原文地址:https://www.cnblogs.com/bianchengnan/p/15725876.html
Copyright © 2011-2022 走看看