Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源
参考内容:http://www.cppblog.com/NWAO/archive/2012/03/08/167403.aspx
在代码开发的过程中,常常碰到编译、链接、运行时加载dll 的问题,简单罗列一下:
1. 未包含头文件:
报错信息可能为: 编译错误 函数/类未定义
2. 包含头文件,未包含库lib/包含的lib不匹配:
报错信息可能为: 链接错误 链接时找不到 函数/类 实现
3. 包含头文件,包含lib库,编译成功,运行时,dll不在当前路径或包含路径(通常path)下 ,也或dll不匹配
报错信息可能为:找读到动态链接库/动态链接库加载失败
上面主要是内容缺失的情况,还有不匹配的情况,造成不匹配的情况有两种情况:
1. 真正的不匹配,头文件*.h 和 *.lib不配套 或 *.lib与*.dll不配套
2. 为“假”的不匹配,匹配的内容、不匹配的内容同时存在,不过由于*.h/lib/dll 查找顺序,查到了不配套的
这种情况比较隐蔽,通常定位起来比较耗时间:
例如:一种情况 头文件 和 lib “假”的不匹配
包含库路径 Lib目录1,Lib目录2 两个路径分别放了旧版本和新版本的 myLibrary.lib 目录1--旧版本 目录2-新版本
包含头文件路径 放置了新的myLibrary.h头文件
在这种情况下,由于lib查找次序的原因,先查找了前面的 目录1-放置了旧版本lib,报错:链接错误 链接时找不到 函数/类 实现
我们修改的话:或是删除掉 目录1中的老的库, 或是调整 lib库包含次序,把目录2放前面
不匹配还有一些其他情况:例如 同名头文件,同名dll,处理的方法也是类似的:一种去掉头文件/lib/dll包含目录中的 错误版本文件,也或调整包含的次序,让其先找到版本匹配的文件。
不匹配情况的处理:
对于缺失的,我们通过添加文件到搜索路径 或 添加搜新的索路径实现,在vc的 项目解决方案-〉vc++目录 处配置 包含文件/库文件。
对于头文件不匹配,这个我们可以借助:直接在vc中找函数/类定义,从而找出当前使用的头文件*.h,调整次序时在vc的 项目解决方案-〉vc++目录-〉win32/x64->包含文件 处调整。
对于lib文件不匹配,我们可以借助vc日志,打开方法:Open project property--->Configuration property--->link-->Genral-->show Process 选择(/VERBOSE:LIB),然後Build就会看到查找的位置,令一方面可以借助everything,查找那里有该库。次序在 vc 的 项目解决方案-〉vc++目录-〉win32/x64->库文件 处调整。
对于运行时dll文件不匹配,通常简单情况下,我们直接把匹配的库copy到运行文件exe的当前目录中,也或 exe程序指定位置,还或path目录中的某个路径,这个视情况而定。
附加-手动指定库的加载次序:
在此处配置: project property--->Configuration property--->link-->Additional Dependies
附加-函数中的使用方法:以下的内容转载自http://www.cppblog.com/woaidongmao/archive/2012/05/31/176937.html
用LoadLibrary实现动态加载类,花了很多时间在dll的路径问题上。
在传入相对路径时,文件的查找顺序比较诡异,在XP sp2以后首先是系统目录开始搜索,以前是首先从当前目录开始搜索。微软认为当前目录是不安全的。所以如果很不巧你的System32下有一个同名的dll时,会造成dll版本的混乱。
解决这个问题,要改用LoadLibraryEx(path,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
另一种方法是先调用SetDllDirectory方法,将要设置的目录会优先开始搜索。
以上两种方法是权宜之计,最值得推荐的方法是用绝对路径而不是相对路径。要获得绝对路径就要知道当前程序的目录。问题来了,怎么获得当前目录呢?
我当时是一拍脑袋,用了GetCurrentDirectory方法。用了才发现,得到的路径并不稳定,有时候会得到莫名其妙的路径,甚至在不同电脑上有不同的结果。
正确的解决方法麻烦了许多,要先AfxGetInstanceHandle()得出模块句柄,然后得到当前模块包含路径的全名GetModuleFileName,最后通过字符串操作,去掉最后一个 / 后的内容,才得到当前路径。
解决了这些问题,LoadLibrary路径没问题,得到结果却是0,GetLastError得到126,找不到指定的模块。我和同事一致认为是dll的其他依赖缺失。用depends打开这个dll,所有依赖都没问题啊,Why?
后来我试着把dll和依赖放的满磁盘到处都是,终于找出了问题所在:
我的程序主模块app.exe和要加载的模块 plugins/plgn1.dll不是在同一级目录下,在用depends打开plgn1.dll时,会在当前目录(/plugins/)下寻找其他依赖,这些依赖都在。
而LoadLibrary加载的模块 plugins/plgn1.dll时,他认为的当前路径是相对主模块app.exe来说的,是程序根目录(/)而不是/plugins/,所以就找不到相关依赖,导致plgn1.dll加载失败。
解决方法:SetDllDirectory方法,设置为plgn1.dll所在的绝对路径。