VC2008发布程序时指定库版本

   用vc2008动态编译(/MD,/MDd)的程序,在进行发布或者部署时,经常会因为目标机器上没有相应的dll库版本而引发“应用程序配置不正确,程序无法启动”问题。而解决方法也不是将vc安装目录下对应的dll库拷贝到程序路径下这么简单,其中涉及到的一些细节还是够大家研究一番的。

   首先我们需要很清楚地了解side-by-side、manifest文件等这些概念,可以参考我博客的文章 详解“由于应用程序配置不正确,应用程序未能启动”

   知道问题产生的原由,我们就明确了解决vc2008程序发布问题的目标:将程序真正链接的dll库文件和程序一起打包,并保证程序的manifest配置能够正确链接到这些库。如果你的vc2008是没有打过补丁的原始版本,那么解决起来还是比较简单的。此时CRT/MFC/ATL库的版本号为9.0.21022.8,我们直接将vc安装目录下\VC\redist\x86\下的Microsoft.VC90.CRT和Microsoft.VC90.MFC两个文件夹及其文件拷贝到分发程序的运行路径下就可以了。如果做安装包的话,将这两个文件夹与应用程序一起打包安装,就可以使程序运行于目标机器上了。

   如果是打了sp1补丁或者sp1atl安全更新补丁的vc2008,解决起来就比较麻烦了,因为你的CRT/MFC/ATL等库版本已经被更新到了9.0.30729.1和9.0.30729.4148(去C:\WINDOWS\WinSxS路径下查看,另外vc2008安装目录下的redist包已经被替换为最新的版本)。你也许会说,库版本被更新了,那么编译出来的程序manifest中指向的链接库版本也应该是最新的,\VC\redist\x86\下的Microsoft.VC90.CRT和Microsoft.VC90.MFC两个文件夹中的库文件也是最新的,那么我们也将这两个文件夹和应用程序一起打包发布不就可以了吗?理论上应该是这样,而且也不应该有不是这样的理由,但是世界上的事情就是这样,总会出现意外,而且等你弄明白了来龙去脉,你还不能对这次意外说些什么。

   比如我们编译一个test.exe程序,那么打开编译输出文件夹中的test.exe.intermediate.manifest文件,或者直接用UltraEdit打开exe文件,你会发现指向的链接库版本竟然是9.0.21022.8。(注意,可以通过工程属性-> Manifest Tool -> Input and Output-> EmbedManifest项设置是否将manifest信息嵌入exe中,一般应该选择“Yes”。)如下面两张图所示。

 

VC2008发布程序时指定库版本



VC2008发布程序时指定库版本

   难道vc2008并没有链接最新版本的runtime库?用DependencyWalker查看一下test.ext实际链接的DLL版本,发现还是最新的9.0.30729.4148版。

 

VC2008发布程序时指定库版本

   这是怎么回事呢?vc2008生成的manifest清单信息竟然是错误的!对于这个问题,有人认为是vc的bug,但是微软似乎也给出了相应的解释。在重新分发应用程序并将其绑定到特定库这篇文章中,微软指出“在编译应用程序时,它会绑定到可用库的原始发行版。即使您的计算机上安装了更高的发行版本,也是如此。例如,如果您的计算机上安装了Visual C++ 2008 SP1,则在此计算机上编译的任何应用程序都仍将依赖 Visual C++ 2008的原始发行版。”这样做的原因是“借助默认绑定行为,可以在获取新发行版之后重新编译您的程序,还可以分发新的可执行文件。已安装所需库的最终用户将只需要新的可执行文件;您不必打包和重新安装最新的库。”也就是说,微软在生成manifest信息的时候加了一个策略,用户在编译程序时,可以选择将程序绑定到RTM版本(原始版本)的运行时,或者当前版本(最新版本)的运行时;选择前者意味着用户分发程序以后,如果更新了运行库版本,需要更新分发出去的程序时,只要在新环境下编译更新程序,然后分发程序本身就可以了,不用同时更新运行库文件(当然如果新程序中依赖新版运行库中的新功能除外),因为此时的manifest信息还是指向原来的版本;如果选择后者,没什么好说的,必须同时更新程序和库。在默认情况下,微软应用前者。这就是为什么我们看到test.exe中的manifest信息和实际链接库的版本会不一样。

   至于具体每个版本对应的策略,大家可以自己去C:\WINDOWS\WinSxS\Policies\下打开相应的.policy文件查看。明白了问题产生的实质,我们就自然有了解决办法,那就是选择“按最新版本”生成程序。在你的代码中(可以选择在stdafx.h文件中),加入以下代码指定CRT和MFC库使用最新版本(实际上是指定manifest信息):

   #define _BIND_TO_CURRENT_CRT_VERSION 1
    #define_BIND_TO_CURRENT_MFC_VERSION 1

   当然,根据需要还可以指定ATL和OPENMP库:

   #define _BIND_TO_CURRENT_ATL_VERSION 1
    #define_BIND_TO_CURRENT_OPENMP_VERSION 1

   或者可以简单地加入

   #define _BIND_TO_CURRENT_VCLIBS_VERSION 1
   指定以上所有库都用最新版本。

   这个方法可以很方便地解决问题,不过我们还有更简单的办法。仔细分析一下前面的分析,会发现其实问题的原因在于程序中manifest信息指向的版本和实际链接的版本对不上号。我们可以用记事本修改“Microsoft.VC90.CRT”和“Microsoft.VC90.MFC”等文件夹下的“Microsoft.VC90.CRT.manifest”和“Microsoft.VC90.MFC.manifest”等文件,将其中的版本号改为“9.0.21022.8”,这样就跟程序中的manifest信息一致了,当然我们的dll库版本应该是实际链接的“9.0.30729.4148”,只是用这个小技巧欺骗一下系统。这样,我们只需要打包绑定到最新版运行库的应用程序、\VC\redist\x86\下的Microsoft.VC90.CRT和Microsoft.VC90.MFC两个文件夹就可以了,只不过此时两个文件夹下“Microsoft.VC90.CRT.manifest”和“Microsoft.VC90.MFC.manifest”文件中的版本号被改成了“9.0.21022.8”。

 

   到此为止,我们终于将vc2008下发布应用程序的问题搞清楚了。幸运的是,在vs2010中我们不用再面对这个问题,而且windowsvista和windows 7系统都自带了最新版的运行库,这个问题也许即将成为历史。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值