
换了个语言包、换了个界面美化包,重新打开程序——界面还是老样子。

或者更直接一点:程序报"找不到资源",而你用工具打开那个 DLL,资源明明就在里面,图标、字符串、对话框模板一样不少。
这两件事看起来是"替换没生效"或"文件有问题",但它们其实是同一类问题的两种表现:资源不是全局放着的,它归属于某一个具体的模块。
要找资源,先得说清"找哪个模块里的"。 这一步没说清,后面全是白费。
很多人对资源有一个默认理解:资源是"这个程序"的资源,放在一起,谁都能取。
实际情况不是这样。
资源是附在每个可执行文件里的一个区段——EXE 有它自己的资源,每个 DLL 也有它自己的资源。 它们是各管各的,彼此不通用。
所以"有没有这个资源"这个问题,必须补全成:
在哪个模块里,有没有这个资源?
少问一半,就会得到“明明有却说没有”这种结论。 也正因为如此,DLL修复工具 在这类问题上同样给不出结论——它确认的是文件层,认不出“归属”这一层。
查找资源的接口,都需要一个"模块句柄"参数。 它决定"去哪个文件里翻"。
HMODULE h = LoadLibraryW(L"resource.dll");
HRSRC r = FindResourceW(h, L"MAIN", RT_DIALOG);关键在于那个 h。
如果它指的是这个 DLL,就在这个 DLL 里找;如果它指的是 EXE,就在 EXE 里找。 同一个资源 ID,传不同的句柄,得到的是完全不同的结果——一个能找到,一个找不到。
而最容易踩的地方是"省略这个参数":省掉它时,默认用的是调用方自己的模块——也就是那个 EXE,而不是你刚加载进来的 DLL。
于是现象就出现了:资源确实在 DLL 里,但查找是在 EXE 里进行的,当然没有。
这里要说明的是:这不是缺陷,而是"必须指定归属"的必然结果。 系统不可能在你没说清的情况下,替你猜是哪一个——因为同一个 ID 在多个模块里同时存在是完全正常的(比如每个模块都有自己的"关于"对话框)。
理解了"资源按模块归属",一个常见做法就顺理成章了。
把界面文字、对话框模板、菜单这些从主程序里抽出来,单独做成一批资源文件——一种语言一个文件。
运行时做两件事:判断当前该用哪种语言 → 加载对应那个文件 → 后续取资源时都带上它的句柄。
于是"切换语言"这件事,本质上是"换掉加载的是哪一份文件",而不是"去改程序里的文字"。
这也解释了为什么汉化和美化补丁通常就是"替换几个 DLL":界面相关的资源集中在那几个文件里,换掉它们,界面就变了。
反过来说:如果某个文字没被替换,很可能是因为它本来就不在资源里——有些字符串是直接写在代码里的,那就不是换资源能解决的。
第一种,加载的不是你替换的那一份。
同一类文件可能存在多份:程序目录里一份、某个子目录里一份、系统目录里一份。而加载哪一份,取决于查找顺序。
还有一种情况是"写进去的和读出来的不是同一个位置"——如果程序装在受保护的目录下,写入可能被改道(这一点前面单独讲过),你替换到的那份,程序根本没读。
第二种,替换的那份没通过校验。
如果模块带了完整性校验(清单、签名),换了内容就对不上,程序可能直接拒绝加载,回退到原有的那一份。 表现就是"换了跟没换一样"。
第三种,程序已经把资源读走了。
有些程序启动时会把资源读进内存或用别的方式缓存,之后的替换对当前这次运行没有影响——必须完全退出再启动,甚至要清掉缓存目录。
第四种,你替换的目录本来就不是它读的那个。
这类问题的共同点:"文件换了"和"程序读到的是新的"是两件事。
这一条和"取不到资源"是反过来的问题,但后果更严重。
取到资源之后,你拿到的是一个指针,它指向那个模块的映射区域。
如果这时把模块卸载了,那个指针就变成了野指针——内存可能还在,但已经不属于任何有效的东西。
所以"用完就卸载"这种想法在这里是错的:
推论很明确:卸载一个模块之前,必须先确认"没有还在使用的资源,也没有由它创建出来的界面对象"。
这条也解释了为什么有些程序"退出时报错"或"关窗口时崩"——关闭顺序错了:先把模块放了,再去销毁依赖它的窗口。
DLL修复工具 覆盖的是第一行——它看的是文件在不在、齐不齐。 而这一篇讲的问题是文件都在、资源也都在,出错的是"去哪个模块里找"和"什么时候能放掉它"。这也是这类工具报"一切正常"的常见场合。
关于 DLL修复工具 处理不了的这一类资源问题,记住四条:
这里可以带走的经验是关于"归属"的:很多"找不到"的问题,其实不是"不存在",而是"不在你以为的那个归属范围里"。
资源有归属,配置有归属,注册项也有归属。 遇到这类问题时,先确认它的归属,再确认它是否存在——顺序反了,就会在一堆"明明在这儿"的证据里绕圈,而真正缺的那一半信息,是"在哪儿找"。
https://www.ijinshan.com/functions/repairdll.html?channel=4105
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。