DLL地狱问题

来源:互联网 发布:安卓版相册制作软件 编辑:程序博客网 时间:2024/04/30 09:22

    今年上班第一天就遇到比较棘手的问题,为外提供的DLL接口在VC6.0中调试和调用都会失败,其图如下

clip_image002

给我的第一反应是Debug调用Release版本的DLL调用的运行期库不一样。所以我将VC6.0的工程改为Relase再调用,其结果一样。为什么呢。我苦思冥想,是不是网上所说的DLL地狱的问题呢。VC6.0调用VS2008写的DLL出错,各自要调用不同的运行期库所前后的问题呢。所以我又用VS2008写了测试代码,先用Debug的来调用DLL接口,其结果一样。这时我又想是Debug调用Release版本的DLL调用的运行期库不一样所导致的,所以将测试代码改为Release版本,结果调用成功。这次我确信是Debug调用Release版本的DLL调用的运行期库不一样导致的原因。但又一想,为什么别人写的DLL都可以被Debug和Realse版本调用和调试啊。没有什么头绪,上网进行人肉搜索,都说什么DLL地狱问题,还有说Debug只能调用Debug的DLL,Release只能调用Release的DLL,不然会出错的。我将信将疑,最终在网上没有什么结果。问题没有解决还要进行测试,我想会不会是自己的代码或工程配置的问题。于是我就将自己所写的代码全部删除,只每剩下VS的代码和接口,重新编译一下,生成的DLL还是不能被加载。这时我确信是工程配置出现的问题了。于是新建一个DLL工程,并用测试代码加载,结果成功了。我将新建的工程配置与我的工程配置进行了比较。结果发现我的工程配置中的清单文件设置与测试工程的设置不一样如下,

clip_image004

这个是测试工程的清单文件设置

clip_image006

这是我的工程设置。很明显我的工程没有生成Manifest文件。于是我将其设置成Yes,重新编译了下,测试代码调用成功。我又用VC6.0写测试代码也可以被调用和调试。我终于长长出了一口气,困扰我两天的问题解决了。为什么没有Manifest文件就不能被调用和加载呢,于是我上网搜索了一下,VC开发工具有不同的版本如VC6.0,VS2003、VS2005、VS2008及VS2010,不同的版本所需的C Runtime Library不一样,版本不匹配时会产生程序失败,微软用manifest来作为版本依赖文件,使”side by side”解决不同版本之间出现的冲突问题。Dll是动态加载共享库,同一个Dll可能被多个程序所使用,而所谓“Dll 地狱”就是当不通程序依赖的Dll相同,但版本不同时,由于系统不能分辨到底哪个是哪个,所以加载错了Dll版本,然后就挂了。于是盖茨就吸取了教训,搞了一个程序集清单的东东,每个程序都要有一个清单,这个清单存再和自己应用程序同名的.manifest文件中,里面列出其所需要的所有依赖,这儿所列出的依赖可不是简单地靠文件明来区分的,而是根据一种叫做“强文件名”的东西区分的,那么什么是强文件名呢?我们来看一下这个.manifest文件便知道了。



 
   
                              name='Microsoft.VC80.CRT'
                        version='8.0.50608.0'
                        processorArchitecture='x86'
                        publicKeyToken='1fc8b3b9a1e18e3b' />
   
 

    我们发现原来这是一个XML格式的文件,其中这一部分指明了其依赖于一个名字叫做Microsoft.VC80.CRT的库。但是我们发现,属性里面还有其它的东东,分别是
type系统类型,version版本号,processorArchitecture平台环境,publicKeyToken公匙(一般用来标示一个公司)……把他们加在一起便成了“强文件名”了,有了这种“强文件名”,我们就可以根据其区分不同的版本、不同的平台……总之,有了这种强文件名,系统中可以有多个不同版本的相同的库共存而不会发生冲突。

    所以,在工程一定要设置程序生成manifest文件,避免DLL地狱的产生。