今天又碰上个头疼的问题,弄半天,记录一下这个过程,省得以后忘。
问题出现
是这么回事,我今天在捣鼓一个之前写的程序,需要调用一个我自己封装的动态链接库(也就是那个dll文件)。本来嘛好好的,运行起来一点问题没有。结果下午我更新点东西,重新编译主程序和那个dll,再一运行,好家伙,直接弹窗报错:“动态链接库(DLL)初始化例程失败”。当时我就有点懵,这咋回事?明明代码改动不大。
初步尝试
遇到这种问题,咱也不能慌,老规矩,先来点简单的。
- 重启程序: 我先把报错的程序关,再重新打开,试两次,还是老样子,看来不是偶然性的问题。
- 重启电脑: 大家都懂的,重启解决90%的问题嘛我就老老实实保存好手头的东西,把电脑重启一遍。心里还琢磨着,说不定是系统哪个犄角旮旯卡住。结果?重启回来,再运行,得,错误依旧。
这下知道,不是简单的重启能搞定的,得往深查查。
深入排查
重启大法不好使,我就开始琢磨这个“初始化例程失败”到底是啥意思。听起来就像是这个dll文件在准备干活之前,内部的一些准备工作没做那可能的原因就多去。
第一步,检查文件本身和路径。
- 我先去看看那个dll文件还在不在它应该在的那个文件夹里。在的,没跑丢。
- 然后我看看文件大小和修改日期,确认是我刚刚编译出来的最新版本。
- 路径?程序能找到它吗?我确认程序查找dll的路径设置是对的,或者说,我把dll直接放在程序的可执行文件(那个exe)同一个目录下,按理说这应该是最稳妥的查找方式。
这一步检查下来,文件本身和路径看起来没啥毛病。
第二步,怀疑依赖项。
我就想,这个dll会不会依赖其他的dll,或者某些系统组件?下午更新的时候,我是不是动啥相关的库?
- 我回忆一下,好像是更新一个第三方库,然后重新编译我的dll。会不会是这个新库有问题,或者跟我系统里其他的啥东西冲突?
- 我尝试着把我这个dll依赖的几个库文件也拷到exe同一个目录下,防止是找不到依赖项。试下,还是不行。
- 有点头大,我隐约记得有些工具能看一个dll到底依赖哪些其他的dll。找找,用类似的小工具扫一下我的dll,确实看到它依赖好几个其他的库,包括我下午更新的那个。版本看着也对得上。
第三步,权限问题?
有时候权限不够也会导致加载失败。虽然以前没遇到过,但死马当活马医。
- 我试着用管理员权限运行我的主程序。右键点击,选择“以管理员身份运行”。你猜怎么着?还是那个错!看来跟权限关系不大。
第四步,是不是驱动或者系统组件的问题?
之前看过网上有人说,显卡驱动更新啥的也可能导致奇怪的dll问题。虽然我这个dll跟显卡八竿子打不着,但万一?
- 我检查下最近有没有更新过啥驱动。好像没有。为保险,我还去设备管理器看看,没发现啥异常的设备。
- 顺便,我还想到系统文件检查。打开命令行(管理员权限),敲个 `sfc /scannow`,让系统自己检查检查重要的系统文件有没有损坏。等它跑完,提示说没发现问题。
第五步,注册DLL?
有些dll需要注册到系统里才能用。虽然我这个是自己写的,理论上不需要,但都到这份上,试试也没坏处。
- 我找到 `*` 这个工具,尝试手动注册我的dll。结果命令行提示我说,这个dll加载失败,找不到指定的模块,或者不是有效的dll什么的。得,此路不通。这反而让我更确信是dll内部或者它的依赖出问题。
找到症结
折腾这么久,有点累。我坐下来,重新捋一遍下午的操作。我改什么?主要是更新那个第三方库,然后用新库重新编译我的dll。会不会是新版的第三方库跟我原来的代码,或者跟系统环境有点“水土不服”?
我决定做个对比试验:
- 回滚代码和库: 我把代码恢复到下午修改之前的版本,并且把那个第三方库也换回旧版本,然后重新编译我的dll。
- 测试: 用这个旧版本的dll替换掉程序目录下的新版本dll。
- 运行程序: 双击运行!这回程序正常启动!没有再弹出那个烦人的“初始化例程失败”的错误!
真相大白! 问题果然出在我下午更新的那个第三方库上。可能是新版本的库有一些隐藏的依赖我没注意到,或者是它内部的初始化逻辑跟我当前的环境有冲突。具体是哪个细节,还得再深入研究那个库才行,但至少现在我知道问题根源在哪。
总结一下
这回解决“DLL初始化例程失败”的过程,也算是一波三折。从最简单的重启,到检查文件、路径、依赖、权限,再到系统层面的检查,通过版本回滚才定位到问题。真是应那句话,排查问题得一步一步来,要有耐心。
这回的实践也提醒我,以后在更新依赖库,特别是第三方库的时候,要格外小心。最好是先在测试环境里充分验证,没问题再用到主程序里,不然就像今天这样,可能得折腾大半天。
好,就记录到这,希望能给以后遇到类似问题的朋友(或者我自己)一点点参考。