在windows xp上运行vs2008编译的Debug应用程序

在软件开发的过程中,有时候我们需要把编译的debug版应用程序复制到开发环境以外的PC上运行测试。通常只需要把编译出exe文件和依赖的DLL复制到测试PC上即可。但是当我把win7系统上使用vs2008 SP1编译出的mfc程序复制到xp上进行测试时,却出现了这样的错误(图1):

在windows xp上运行vs2008编译的Debug应用程序

这是怎么回事儿呢?如果说是因为缺少依赖的dll,通常情况下应该出现这样的错误(图2)才对。

在windows xp上运行vs2008编译的Debug应用程序

 如果不是dll的原因,那究竟是什么造成图1所示的错误呢?

这是因为微软在VS2005以后采用了新的程序部署技术--manifest清单文件。这种技术使得不同版本VS开发的应用程序可以在同一个操作系统中运行。例如,程序A运行时需要版本号为9.0.21022.8的mfc90ud.dll,程序B运行时需要版本号为9.0.30729.6161的mfc90ud.dll,如果安装A时将mfc90ud.dll复制到了系统目录中,之后安装B程序时使用同名的mfc90ud.dll覆盖了之前的文件,此时A程序可能无法正常运行。我们当然可以把mfc90ud.dll安装在程序各自的私有目录下,但这显然不是一个优雅的方式,假如C程序也依赖和A程序相同版本的mfc90ud.dll,我们不得不在C程序目录下也保存一个完全相同的mfc90ud.dll。

   使用这种技术之后,程序运行时加载dll的方式和以前不同了。程序不再像从前那样简单地去预定的目录依次查找dll。程序不仅需要知道所依赖的dll的文件名,还要知道dll的版本号等信息。为此当我们使用VS2008等开发工具生成exe文件时,同时还生成了和这个exe相关的manifest文件,这个文件以xml格式详细描述了exe依赖的dll以及版本信息,示例如下(图3):

    在windows xp上运行vs2008编译的Debug应用程序

使用VS2008生成mfc程序时,默认将程序相关的manifest文件生成在$(IntDir)目录下,文件名是$(TargetFileName).intermediate.manifest。在工程的Properties->Configuration Properties->Linker->Manifest File可以进行修改(图4)

    在windows xp上运行vs2008编译的Debug应用程序

并且在默认情况下,VS工具会把这个xml文件的内容嵌入exe文件中。你可以把Properties->Configuratio Properties->Manifest Tool->Input and Output->Embed Manifest设置为No使manifest信息不嵌入exe文件中(图5),这样可以减小exe文件的尺寸。

在windows xp上运行vs2008编译的Debug应用程序

   

微软给我们提供了两种程序部署方式,共享并行程序集和私有程序集。共享并行程序集的部署方式超出了本文的主题,不再赘述。私有程序集简单说就是把dll部署在exe文件所在的目录。这种方式方便测试以后干净地删除文件,因此我们使用这种部署方式。当在开发环境以外的主机上部署程序时,不仅要复制exe和dll文件,还要把相关的manifest复制到exe所在目录中。

因此本例中需要复制 "mfc90ud.dll Microsoft.VC90.DebugMFC.manifest msvcr90d.dll  Microsoft.VC90.DebugCRT.manifest"4个文件到exe所在的目录。这些文件在VS2008的安装目录下,具体目录是

Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC90.DebugCRT

Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC90.DebugMFC

如果使用了默认设置,在exe文件嵌入manifest,则只需要复制exe文件。如果修改了设置,则需要把exe相关的manifest文件一同复制过去。这样就能在xp上使用VS2008编译出的Debug版程序了。

特别注意,VS2008有一个bug。使用VS2008生成的manifest文件中指明exe依赖的动态库版本为9.0.21022.8(见图3)。实际上exe依赖的dll版本是9.0.30729.6161,我们在开发环境中启动调试,在Debug->Windows->Modules窗口中可以看到exe实际加载的dll版本,如下图(图6)

在windows xp上运行vs2008编译的Debug应用程序

 因此使用上述方法在xp上部署了Debug版程序后,运行仍会出错。有两个办法来解决此bug。一是修改project使manifest文件生成正确的信息,在project中定义一个宏,_BIND_TO_CURRENT_VCLIBS_VERSION即可。二是在测试机上修改dll的manifest文件,把version改为"9.0.21022.8",程序即可正确运行。