记一次曲折的多资源文件拆分折腾过程——过程是曲折的,结果是美好的
共 3287字,需浏览 7分钟
·
2021-09-07 15:52
缘起
最近这些天,我一有时间就捣鼓 .rc
。用 git
管理过 .rc
文件的小伙伴儿应该都知道,.rc
文件会被 git
默认当作二进制文件来管理。每次合并代码的时候,只要涉及到 .rc
文件的变更,很大概率会报冲突,而且工具不能很好的解决,只能手动解决。为了解决这个问题,我想到了两个方案:
让 git
把.rc
文件当成普通文件来管理。把一个大的 .rc
文件拆成多个小的.rc
文件,这样可以有效的降低冲突的概率。
这两个方案相互之间没有任何冲突,所以这次折腾的时候,这两个方案是同时进行的。本以为没什么值得写的,没想到收获了意外惊喜,于是有了本篇总结。
拆分 rc
按照微软官方文档 TN035: Using Multiple Resource Files and Header Files with Visual C++ 的指示,很快就拆分好了。满心欢喜的准备编译运行,验收成果。
没想到……
初遇错误
编译很快结束了,不过 vs
报告了下图所示的编译错误:
![](https://filescdn.proginn.com/d248d02fceacc66c5e55e2ed86459228/5c0106ffd53eb435f33056e0ad78c8ba.webp)
乍一看有一点懵,不过仔细看文件内容后知道怎么回事了。原来这是一个“老朋友”了,之前遇到过。不是什么大问题,只需要在后面多加一个空行就行了。
温馨提示:
如果在
resource.h
中包含自定义的头文件时,也需要在被包含的头文件的末尾加一个空行。否则也会报错。
在末尾加好空行后,再次编译,成功,正常运行。
![](https://filescdn.proginn.com/96edd960300f6c8259c427f41a1c6a6c/ba45038acb175244a51319813206e946.webp)
解决了在同一工程中使用多个 .rc
的问题,下一个问题是让 .git
不再把 .rc
文件当成二进制文件来管理。默认情况下,.rc
文件会被当成 binary file
来管理的,当 .rc
中有差异的时候,在命令行中执行 git diff
命令,不能显示出有意义的信息。
![](https://filescdn.proginn.com/a2851809e18a59c25a55503bc9031e75/8f0ba6213a0fd6439f774a1216aa31c5.webp)
修改 git 设置
按照 gitattribtes帮助文档 中的说明,我在项目根目录建立了 .gitattributes
文件,把 .rc
和 .rc2
文件都当成 UTF-16
来管理,这样再冲突的时候就可以比较差异了。
![](https://filescdn.proginn.com/7c0071ff1c97465d8035656ae36884b3/39e1dba376bb8acde2bcd9bcb3fae0ad.webp)
说明:
因为现有项目中的
.rc
文件都被当成了二进制文件,所以我在.gitattributes
中末尾的位置把旧的.rc
和.rc2
文件强制设置为了binary
。
设置好 .gitattributes
文件后,手动修改 .rc
文件内容,然后执行 git diff
查看差异。结果如下图,这次显示的差异简直完美。以说明新增加的设置是生效的。
![](https://filescdn.proginn.com/70c7651dc89efb2087982fea085b89e6/584de1a889ad6eb05984ec7128791d7a.webp)
本以为本次折腾就这么顺利的结束了,可以打扫战场,编写操作文档,收工了。
没想到……
高兴的太早了
撤销完变更后,编译,居然出现了下图中的错误:
![](https://filescdn.proginn.com/73182cbee79e08960bc2b733b5c5fc46/d6cec46ec650c7eb5326b2506ae471f1.webp)
这是什么错误?一脸懵逼,难道上面哪个地方多写了 #endif
导致不匹配了?赶紧把改动过的文件都检查一遍,尤其是刚刚改动过的文件。
![](https://filescdn.proginn.com/584444bf817e00808f0ad3eb1280b067/110cb869a9815981895e0e38750cca9a.webp)
每个文件都反反复复看了好几遍,什么问题都没看出来。#if
和 #endif
都是成对儿的。这可如何是好,网上搜索 error RC1020
,没有一条能解决我遇到的问题。
绝望
看了很长时间也没发现哪不对,于是我开始玄学了。
难道是在
.rc
中不能加重复包含的保护?不应该啊,在其它地方看到过类似的用法,还特意模仿着写的。不管三七二十一了,删除,编译,依然报错。难道
#include
的头文件路径不对?调整包含路径,依然报错。难道不能在
.rc
中包含头文件?不应该啊,默认生成的.rc
就包含了resource.h
啊。删除,可想而知,依然报错。难道……
就这样排除了很多种“可能性”,试了很多方案,都没有用。但是得到了一个结论:只要包含这个 .rc
文件,编译就有问题。要不是刚开始在拆分完 .rc
后已经成功运行程序了,我都有些怀疑是不是不支持在同一个工程中使用多个 .rc
了。
柳暗花明
实在不知道是哪里出问题了,于是起来接了杯水,在回座位的路上,脑子里突然蹦出来一个想法:双击打开有问题的 .rc
文件看看能不能看出点什么门道来。如下图:
![](https://filescdn.proginn.com/97eaec62c269f44011afebe0566a03ac/cf97278c822088cc561dc1b467a06859.webp)
嗯?怎么是空的?我的对话框去哪了?(内心一阵窃喜)赶紧打开一个正常的 .rc
文件看看,如下图:
![](https://filescdn.proginn.com/d6781fa87c7e5beb3d0450aff1fb9fbe/04fbb07b2243a2c4752276a56f3817d0.webp)
该有的都有。手动把正常显示的对话框的内容拷贝到有问题的 .rc
中,看看能否打开,发现居然还是打不开!!!炸了,赶紧通过 beyond compare
对比看看。
![](https://filescdn.proginn.com/9dcedcf43e18afdd243fd2253af149d1/52a871612a83a8d0f3c7cb65ac21a7ad.webp)
虽然提示 Difference not found
,但是如果仔细看的话,两边的编码是不同的。为了进一步确认,于是打开 Hex Editor
查看文件头,果然不一样。
正常的 .rc
文件是按小端存储的—— FF FE
,也就是UTF16 LE with Bom
。有问题的 .rc
文件是按大端存储的—— FE FF
,也就是 UTF16 BE With Bom
。
知道了原因,于是赶紧修改有问题的 .rc
文件为小端模式.
警告:
不能直接修改文件头,否则打开时文件内容不对。可以使用 notepad.exe 打开有问题的 .rc 文件,然后另存为的时候选
UTF16 LE
即可。save-as-utf16-le
再次双击打开发现可以正常打开了,并且编译也没问题了。特地贴一张编译通过的截图,我太难了。
![](https://filescdn.proginn.com/a0614992d9a62526c3f3b16efeaae22e/dab02a727270dda5e365f5047d6e5197.webp)
又遇错误
本以为编译都通过了,应该就万事大吉了吧,没想到运行的时候直接崩溃了。我也要崩溃了。
![](https://filescdn.proginn.com/ea2a76cddebe98d2038e42e72e26daae/a9a4d08883d2ff0a5cc94d8ffa5b2d67.webp)
说明:因为我设置了
windbg
为JIT
调试器,所以程序崩溃后直接到windbg
中了。
在 vs
中按 F10
启动,单步跟踪,很快就发现是获取对话框的时候失败了。
.rc
问题,难道生成的程序的资源段有问题了?使用 CFF Explorer
打开程序查看资源段,如下图:![](https://filescdn.proginn.com/4c4f2eda0c92cd47b6134608ffd556b2/0b28fc4181a5bc21149589ec49d432af.webp)
果然,程序资源段中没有任何对话框,难怪查找对话框的时候找不到。看来跟刚才的 .rc
是一个问题,查看对应的 .rc
文件的文件编码,果然是一样的问题。修改文件编码,然后重新生成,启动后终于正常了。
总结
这次的折腾真是一波三折,有点意思。几个关键点总结如下:
如果想在 resource.h
中#include
自定义的头文件,务必确保自定义头文件结尾多留一个空行,同样的道理,如果一个.rc
文件包含在另外一个.rc
文件中,也务必在结尾多留一个空行。.rc
文件要求是UTF-16 LE With Bom
格式的,一定不能搞错。p.s. 在查资料过程中,发现也可以指定为UTF8
格式,但是我没成功。CFF Explorer
真的是查看PE
的好帮手,你值得拥有。程序是最讲道理的,对就是对,不对就是不对。遇到诡异问题,一定不能迷信,也不能瞎猜。
参考资料
https://docs.microsoft.com/en-us/cpp/mfc/tn035-using-multiple-resource-files-and-header-files-with-visual-cpp?view=msvc-160 https://git-scm.com/docs/gitattributes
未完待续
虽然问题解决了,但是为什么 .rc
文件的编码变了?而且还变错了。会是 git
的 bug
吗?
敬请期待后续文章……