有时候,我们用Visual C++开发的程序,发布到一台没有开发环境的电脑上,有可能出现错误,应用程序根本就运行不起来,如下图所示:
它提示side by side配置不正确,这种情况一般都是找不到C运行库(CRT)而引起的。
一、什么是side by side
在Windows XP SP2以后,Windows引入了side by side执行的概念,这个概念本来是.NET提出来的,但是Windows后来将这个概念集成到操作系统层面上来了。side by side提出不同版本的DLL文件可以同时存在于一个系统里面。例如;
1.假如你写了一个C++程序A,用到了MFC8.0(这个版本是随Visual Studio 2005发布的)。
2.之后你的电脑又安装了Visual Studio 2008,系统从2005升级到2008,2008的MFC库是9.0版本的,这个时候你的操作系统里面就会有两个版本的MFC库,分别是8.0和9.0。
3.你在Visual Studio 2008下面开发了程序B,B依赖于MFC 9.0版本的库。
4.如果你运行程序A,系统会把MFC 8.0的库加载到进程中去,如果运行程序B,系统就会加载MFC 9.0的库,这就是side by side的概念。
那么这下问题就来了,系统是怎么知道一个程序它到底依赖于哪个库?VS2005/VS2008采用了新的程序部署技术,这就是接下来要说的manifest文件。
二、manifest文件是什么
manifest清单文件类似于makefile文件,它定义了程序运行的依赖关系(程序运行所需要的DLL库的名称、版本等信息)。操作系统加载一个程序时,会检查其PE格式里面所依赖的DLL信息,也会查看这个程序对应的manifest文件,一般情况下,.manifest文件名与程序名称相同。如程序A的manifest文件就是A.manifest。有些程序把manifest文件嵌入到资源文件中了,这也就看到到与它对应的manifest文件原因,通常一个manifest文件的格式如下图所示:
这个文件一般在程序编译生成目录里面,我这里是打开一个DEBUG版本的,所以需要的assembly name就是DebugCRT,注意我用黑色框起来的就是当前程序所需运行库的版本。这说明当前程序需要的是9.0.21022.8。
下面这个.manifest是VC 9.0 的运行库的清单文件,它的版本是9.0.30729.4148。我们的程序依赖的库版本与9.0的版本不一致,那怎么办呀?一种很简单的方法,把9.0的库的.manifet文件的版本号改为当前文件的.manifest的版本号,反正使两个版本号一致。
在VS2005和VS2008中,可以在工程属性设置中,将.manifest文件嵌入到程序中。如下图所示:
用红色标识的是文件生成的路径,第一个选项框就可以指定是否生成.manifest文件。
另外要注意,由于vc2005/vc2008与.net集成,导致出现一个新的概念:在.net中,将exe、dll都看成“程序集(assemble)”,每个程序集(assemble)都附带有一个manifest清单文件,因此使得vc2005/vc2008的CRT(C 运行时库)、MFC、ATL等dll库都附带有一个manifest清单文件。
归根结底是由于老版本的系统没有我们开发的程序运行所需要的基本运行时库(2k、xp系统只有vc6的一些dll库,而没有vc2005、vc2008所需要的dll库以及相应的manifest清单文件,而在vista系统或者即将到来的windows 7系统上则包含有vc2005、vc2008的dll库和manifest清单文件)
三、解决方案
将VS安装目录下面的VC运行库拷贝到你的应用程序的目录下面,进入到如下目录:
D:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86(Release版本的)
D:\Program Files\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist(Debug版本的)
├─Microsoft.VC90.ATL
│ atl90.dll
│ Microsoft.VC90.ATL.manifest
│
├─Microsoft.VC90.CRT
│ Microsoft.VC90.CRT.manifest
│ msvcm90.dll
│ msvcp90.dll
│ msvcr90.dll
│
├─Microsoft.VC90.MFC
│ mfc90.dll
│ mfc90u.dll
│ mfcm90.dll
│ mfcm90u.dll
│ Microsoft.VC90.MFC.manifest
把这些文件都拷贝到你EXE的执行路径下面,由于上面的应用程序依赖的库版本是9.0.21022.8的,所以你可能要把VC运行库里的版本改为与你应用程序相同的版本。