VS2008部署问题

 

参考资料

1、VS2005解决"应用程序配置不正确,程序无法启动"问题

2、VS2005安装文件 "由于应用程序配置不正确,应用程序未能启动"

3、Microsoft Visual C++ 2008发布程序的部署问题

4VC编写的程序不能在其他机器上运行的解决方案

新增(先看看上面的4个链接之后,遇到问题之后再看下面的几个链接)

5关于vs2008 sp1 C++生成的 manifest中运行库版本号的问题 (推荐1)

6、在VC++2008的项目中,如何显示地指定要使用的C++库的版本? (推荐2)

7、VC9 SP1 generates manifests with the wrong version number

ps:有人认为这是一个bug,并汇报到ms网站上,但“推荐1”认为这不是一个bug

8、VC Runtime Binding...(ms的官方blog对这个问题的解释)

关于VC运行时绑定(上面链接的中文翻译)

9、部署 (C++)推荐,比较难看懂

关于链接9下几个比较有用的链接:

程序集搜索顺序英文,主要讲的是CRT、MFC等的DLL和manifest文件的部署方式

选择部署方法

使用 Program Files/Microsoft Visual Studio 8/VC/Redist目录中提供的文件将特定 Visual C++程序集作为应用程序的私有程序集安装。允许没有管理员权限的用户安装应用程序或可以通过共享运行应用程序时,建议使用这种方法。有关示例,请参见如何:使用 XCopy进行部署。(摘自:选择部署方法

 

总结如下:

使用vs2008/vs2008开发的程序有2种部署方法:共享并行程序集和私有程序集部署方法

所谓的共享并行程序集部署方法是指程序依赖的CRTMFCATLDLL和manifest文件位于目标机器上的c:/windows/winsxs目录中,发布程序的时候只需要将程序拷贝到目标机器上就可以了私有程序集部署方法指的是发布程序程序的时候,将所依赖的crt、mfc、atl的dll放在程序的当前目录下

 

对于release版程序

比较的简单的方法采用共享程序集的方式来部署,安装vcredist.exeMicrosoft Visual C++ 2008 SP1 Redistributable Package (x86)

也可以采用下面debug程序的私有程序集的部署方法

 

对于debug版本程序

若目标机器安装了VS开发环境(vs2005 sp1/vs2008 sp1),则在机器上同时也安装了共享并行程序集,包含各个版本的dll(8.0、9.0版本,位于C:/Windows/Winsxs目录下),则不需做任何的部署,直接将需要发布的程序拷贝到目标机器上就可以了,这和release版程序的发布方式是一样的

在没有安装VS开发环境(安装了vs2005 sp1/vs2008 sp1)的机器上,只能采用私有程序集的方式来部署(因为vcredist.exe只安装了release版的CRT、MFC、ATL的DLL和manifest文件,没有对应的debug版本)

已知的2种方法:(针对vs2008 sp1,安装了sp1之后,在系统上会存在两个版本的CRT、MFC、ATL的DLL:9.0.21022.89.0.30729.1

1、使当前程序的manifest文件中依赖项的版本与vc安装目录下的redist目录下的dll的版本一致,均为9.0.30729.1

方法:

a、在编译项目时定义一个符号_BIND_TO_CURRENT_VCLIBS_VERSION,该符号定义于C:/Program Files/Microsoft Visual Studio 9.0/VC/include/crtassem.h 文件中(假设VC安装在c盘),这样使得编译后的程序的manifest依赖于CRT 9.0.30729.1版本(同样的,对于MFC也应该定义一个类似的符号,大家可以自己在VC的include目录下搜索“9.0.30729.1”或“9.0.21022.8”,就可以找到对应的定义该符号的头文件)

b、通过外部工具修改生成的exe或dll中manifest文件(好像windows sdk中的mt.exe可以做到,不过关于这个工具的资料十分的少)

2、将VC安装目录下的redist目录下(C:/Program Files/Microsoft Visual Studio 9.0/VC/redist)的Microsoft.VC90.CRT拷贝到要发布的程序的当前目录下,修改Microsoft.VC90.CRT目录中的Microsoft.VC90.CRT.manifest文件中的版本号,改成9.0.21022.8,这样使得程序误以为该目录下的vc的dll版本是9.0.21022.8(实质上仍然是9.0.30729.1版本)

 

说明:

1、链接4 的说法是错误的,根据我自己的实验,如果采用私有程序集的部署方法,必须保证manifest文件中的版本号都是相等的,不存在要发布的程序的manifest文件中的版本号大于等于依赖项(CRT、MFC、ATL的dll)的版本号的说法

2、采用共享并行程序集部署方式发布的程序,会自动根据所谓的“policy”(位于C:/WINDOWS/WinSxS/Policies目录下)进行跳转(由低版本号向高版本号跳转);例如程序中的manifest的版本号为9.0.21022.8而实际上程序是用vc2008 sp1编译的(版本号为9.0.30729.1,在程序实际执行的时候,会根据

x86_policy.9.0.Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_x-ww_037be232目录下的9.0.30729.1.policy文件可以用记事本打开该文件中的内容选择9.0.30729.1版本的debugCRT

 

 

我个人推荐的阅读顺序:① 先看前面的4个链接,大致有点印象,知道什么是manifest、如何查看manifest文件的内容(能力强的话,也可以自己编写manifest文件)、在vc中如何查看编译过程中生成的manifest文件内容、知道C:/WINDOWS/WinSxS/目录是干什么的、知道vcredist.exe这个程序; ② 再尝试着看看链接7、8、9,这些链接的文章内容十分的晦涩,有的还是英文的,需要有点耐心看; ③ 最后仔细的看看链接5、6,并多多试验(特别推荐链接5,这个链接中的内容十分的详细)

 

参考资料: 应用程序配置不正确,程序无法启动 的解决方法资料收集

内容我就不copy了,大家可以自己去看,总来说产生这个问题的原因可以归结如下:

vc2005/vc2008采用了新的程序部署技术(manifest清单文件),manifest清单文件实际上类似于我们常用的makefile文件,它定义了程序运行的依赖关系(程序运行所需要的dll库的名称、版本等)。

程序运行,首先根据manifest清单文件(这个文件可以嵌入到exe或dll中,或者单独生成外部文件,可以通过vc2005/vc2008的编译选项控制:工程“属性”->“配置属性”->“清单工具”->“输入输出”->“嵌入清单文件”,选择“是”或“否”来控制)来查找程序运行需要的dll库的名称、版本等,如果所在的系统中没有程序运行所需要的dll库和相应的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清单文件)

ps:上面的那段话说的有点幼稚和简单了,这里涉及到很多的问题:程序的升级更新、vs的补丁、库的版本问题等等,不是简单的拷贝、粘贴就能解决的。。。

 

举个例子:(在XP SP3系统下)

使用vc2008 express sp1版(没有mfc、atl),新建一个“HelloWorld”的“win32控制台应用程序”工程,在release下编译,此时默认的编译选项:(在这里我们只关注与我们的问题相关的几个选项)

1、工程“属性”->“配置属性”->“c/c++”->“代码生成”->“运行库”

默认选项为/MD(release)、/MDd(debug),对这几个编译选项不清楚的可以参见: VC运行库版本不同导致链接.LIB静态库时发生重复定义问题的一个案例分析和总结

2、工程“属性”->“配置属性”->“清单工具”->“输入输出”->“嵌入清单文件”

默认选项为“是”(表示将manifest清单文件嵌入到程序中);当然,我们也可以选择“否”,从而单独生成一个manifest清单文件,不过这会增加不必要的依赖项,因此不建议选择“否”。

编译->链接之后在“ HelloWorld ”工程的release或debug目录下,我们能够看到一个HelloWorld.exe.intermediate.manifest清单文件(根据编译选项,见上,vc2008将manifest清单文件嵌入到了exe程序中,HelloWorld.exe.intermediate.manifest清单文件是一个临时文件,但它的内容与嵌入到exe程序的manifest文件是一样的),用文本编辑器打开该文件(用“记事本”也行,不过格式太乱,看不清楚内容,推荐使用vim或其它的文本编辑器查看),大致内容如下:

ps:在网上看到另外的一个方法,用记事本打开exe或dll程序,查看嵌入到exe或dll中的manifest清单文件,方法:“打开记事本,然后将exe或dll拖入到记事本中,当然了,肯定会出现大段的乱码,没关系,直接往后看,就能发现类似于下面的内容的部分”

XML语言: HelloWorld.exe.intermediate.manifest

01 <?xml version='1.0' encoding='UTF-8' standalone='yes'?>

02 <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>

03 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">

04      <security>

05        <requestedPrivileges>

06          <requestedExecutionLevel level='asInvoker' uiAccess='false' />

07        </requestedPrivileges>

08      </security>

09 </trustInfo>

10 <dependency>

11      <dependentAssembly>

12        <assemblyIdentity type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />

13      </dependentAssembly>

14 </dependency>

15 </assembly>

我们重点查看红色部分,这说明编译后的exe程序依赖于vc90(也即vc2008)的CRT(C运行时库),版本9.0.210022.8(这是由于使用/MD选项,程序动态的依赖于CRT,如果使用/MT选项,则会将CRT静态链接到程序中,当然,这会使程序的尺寸急剧的增长,大概有10倍的大小差距)

当exe程序执行时,它会根据嵌入的manifest文件查找相应的依赖项,在这个HelloWorld.exe程序中,它依赖于vc90 CRT,因此它会在“C:/WINDOWS/WinSxS”和“当前目录”下查找相应的dll库以及manifest文件,(这里指的是xp系统,不考虑vista系统,具体的参见:程序集搜索顺序)

在我的机器上有2个版本的vc90 CRT(由于安装了vc2008 express sp1)

vc90 CRT的dll库位于(9.0.21022.8版本)“C:/WINDOWS/WinSxS/x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375”

相应的manifest文件则位于“C:/WINDOWS/WinSxS/Manifests/x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375.manifest”

vc90 CRT的dll库位于(9.0.30729版本)“C:/WINDOWS/WinSxS/x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_6f74963e”

相应的manifest文件则位于“C:/WINDOWS/WinSxS/Manifests/x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_6f74963e.manifest”

在这里我们就有一个疑问了,我们的开发环境是vc2008 express sp1,那么我们的程序链接的CRT版本应该是9.0.30729版本的啊?(这个不是我瞎说的,大家可以用dependency walker来查看程序实际链接的DLL版本),为什么在manifest文件中依赖的CRT却是9.0.21022.8版本的?这里就涉及到一个新的名词“policy ",操作系统会根据C:/WINDOWS/WinSxS/Policies/x86_policy.9.0.Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_x-ww_b7353f75/9.0.30729.1.policy文件的内容,进行dll版本的跳转(重点看深蓝斜体字部分)从而选择了9.0.30729版本的vc90 CRT (这个所谓的“policy跳转”是道听途说来的,具体的英文资料藏在microsoft的什么地方我就不得而知了。里面夹带了一些我自己的主观猜测,不然的话,没有办法解释manifest版本号9.0.21022.8是,而实际链接的dll的版本号却是9.0.30729)

XML语言: 9.0.30729.1.policy

01 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>

02 <!-- Copyright (c) Microsoft Corporation. All rights reserved. -->

03 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

04     <assemblyIdentity type="win32-policy" name="policy.9.0.Microsoft.VC90.CRT" version="9.0.30729.1" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>

05     <dependency>

06         <dependentAssembly>

07             <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>

08             <bindingRedirect oldVersion="9.0.20718.0-9.0.21022.8" newVersion="9.0.30729.1"/>

09             <bindingRedirect oldVersion="9.0.30201.0-9.0.30729.1" newVersion="9.0.30729.1"/>

10         </dependentAssembly>

11     </dependency>

12 </assembly>

 

如果我们将这个HelloWorld.exe拷贝到其它的机器上(没有安装vc2008 sp1或Microsoft Visual C++ 2008 SP1 Redistributable Package (x86)),则程序因为没能找到vc90 CRT,而不能运行,弹出“应用程序配置不正确,程序无法启动”对话框。

根据参考资料的文章中的内容,对于release版程序,有一个简单的办法就是安装“vcredist_x86.exe”,文件大小4M左右,自动安装在“C:/WINDOWS/WinSxS”目录下,包含了CRT、MFC、ATL等库的dll和manifest清单文件;整个安装时间不到1分钟。

如果机器上安装了vc2005/vc2008,则会自动的安装vcredist_x86.exe程序,安装后在“控制面板”->“添加删除程序”中有一项“Microsoft Visual c++ 2008 Redistributable - x86 9.0.3.729”(我安装的是Microsoft Visual C++ 2008 SP1 Redistributable Package (x86) c

注意:要根据编译器版本以及vc2005/vc2008是否安装了sp1补丁进行选择对应的vcredist.exe版本

 

 

上述的解决办法我称之为共享程序集部署方法,同样的我们也可以采用私有程序集的部署方式来发布程序

Helloworld例子的私有程序集的部署方法:(针对release版本,仍然是采用上面的例子

,采用参考资料中提到的第2中私有程序集部署方法:将Microsoft.VC90.CRT目录下的manifest文件的版本号修改为9.0.21022.8

1、将编译后的程序拷贝到一个目录下,假定为d:/helloworld

2、将vc安装目录下的redist/x86目录下的Microsoft.VC90.CRT目录拷贝到d:/helloworld(假定vs安装在C:/Program Files/Microsoft Visual Studio 9.0,则vc安装目录为C:/Program Files/Microsoft Visual Studio 9.0/VC)

3、将Microsoft.VC90.CRT目录下的manifest文件的版本号修改为9.0.21022.8用记事本打开修改

最终发布程序的目录结构

D:/helloworld

      |--helloworld.exe

      |--Microsoft.VC90.CRT

                     |--Microsoft.VC90.CRT.manifest

                    |--msvcm90.dll

                     |--msvcp90.dll

                    |--msvcr90.dll

这个时候,程序的manifest文件(已经内嵌到exe中了)依赖的vc90 CRT的版本号和Microsoft.VC90.CRT.manifest文件的版本号对应一致,都是9.0.21022.8但是要注意的是,我们的helloworld程序实际上依赖的vc90 CRT版本是9.0.30729版本这里只是采用了一种欺骗的方法,因为我们编译时链接的CRT的版本是9.0.30729版本)

 

下面是一片英文博客文章和评论

http://blog.kalmbach-software.de/2009/05/27/deployment-of-vc2008-apps-without-installing-anything/

 

 

If you create a default CRT/MFC application with VS2008, this application will not run on other computers. You application will complain with
“This application has failed to start because the application configuration is incorrect”.

The problem is that by default VC2008 uses the DLL-version of the CRT/MFC. These DLLs are not pre-installed on any OS.
To overcome this problem, you have tree options:

  1. Statically link to the CRT/MFC
  2. Use vcredist_x86.exe / vcredist_x64.exe to install the DLLs in the system
  3. Deploy the CRT/MFC DLLs with your application (in the same directory)

In the following I will explain the last option. Especially in conjunction with VS2008 service pack 1 (SP1). Because this leads to a little bit more compications in ApppLocal deployment.

In general, it is very easy to deploy your application with the needed CRT/MFC DLLs.
Just copy the contents of the directory

  • C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/redist/x86/Microsoft.VC90.CRT
  • C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/redist/x86/Microsoft.VC90.MFC

into the same directory as your application. Then you should have the following files in your app-folder:

Microsoft.VC90.CRT.manifest
msvcr90.dll
msvcp90.dll
msvcm90.dll
Microsoft.VC90.MFC.manifest
mfc90.dll
mfc90u.dll
mfcm90.dll
mfcm90u.dll

Then your application works on an other computer!

BUT: This does not work, if you installed VS2008-SP1 :-(

The problem with VS2008 SP1 is: It overwrites all files in the “VC/redist” directory with the new version. This is not really bad. The problem is: It has a newer version number inside the manifest files. But if you compile your application with VS2008-SP1 it write the RTM-version into the application manifest! Now the version number in your application manifest does not match the version in the “new” CRT/MFC manifest. Therefore it will refuse to load these DLLs and your application cannot start.

The simplest way to overcome this problem is by changing the “Microsoft.VC90.CRT.manifest” and “Microsoft.VC90.MFC.manifest” files. Replace the version attribute in both Microfot.*.manifest files from “9.0.30729.1″ (or whatever version/SP you have) to the version number in your applications-manifest (which is normally “9.0.21022.8″ (RTM)).
Old:

version="9.0.30729.1"

New:

version="9.0.21022.8"

Then your application will work on an OS without installing anything.

Alternatively, you can change your applications manifest, so that it uses the new version number. This can easily done by defining

#define _BIND_TO_CURRENT_VCLIBS_VERSION 1

in stdafx.h (at the top) or in your project settings. This will embed the actual CRT/MFC-version into your applications manifest (works starting with VS2008-SP1).
Also, if you use new features from the MFC-feature-pack, you should always define this!

Just a small note: You should be aware, that this “AppLocal” installation is not really “AppLocal”… it is only AppLocal, if the vcredist_*.exe was not installed. If the vcredist_*.exe is installed, then the DLLs from the WinSxS directory will be used. If you want to prevent this, you can do a really AppLocal deployment.

A small addition: If you write .NET-apps (/clr) you still must install the .NET Framework redistributable.

But the goood news is: Starting with VC2010, the manifest (WinSxS) is gone ;)

11 Responses to “Deployment of VC2008 apps without installing anything”

  1. Ezmail Says:

    Hi.. Thanks for the information.. Currently I have the same problem, but I use VC 2005. Is that same steps?

  2. jkalmbach Says:

    Yes. There are the same steps… expect the version numbers are different; you need to look at your applications-manifest to lookup the correct version number.

  3. Michiel Says:

    Would it be possible to link to the VC80 libraries within VC2008 ?
    We have a lot of systems around with the 2005 redist already installed. We would like to develop using VC2008 but when we update our software we don’t like to install a lot of new dependencies.
    Thx

  4. jkalmbach Says:

    No, this is not possible.
    The easiest way is to use static linking:
    http://blog.kalmbach-software.de/2008/03/03/screencast-statically-link-to-the-c-runtime-to-prevent-vcredist-and-overcome-application-configuration-problems/

  5. Chuck Says:

    I have updated my dlls and manifest files to the new version, 9.0.30729.4148 and my exe won’t run. I have opened my .exe file and it is looking for old version (9.0.30729.1). I found the ***.exe.intermediate.manifest in the Release dir. It says old version. I can’t figure out what creates ***.exe.intermediate.manifest since it is created during the build.

  6. Chuck Says:

    Figured it out…It’s a long story. If anyone wants to hear it, let me know.

  7. Svetoslav Kyuchukov Says:

    Hello Jochen,

    Thanks for the useful article. The described technique work also fine for deploying of debug versions, by working with corresponding debug folders and manifest files:
    (Microsoft.VC90.DebugCRT, Microsoft.VC90.DebugCRT.manifest, etc.)
    Currently I work on a VS2008 solution that contain 4 executables and 18 dlls, and deploying debugs is a practical (for Testers, PMs, etc. purposes).

    And further, even the Common Control Dll (comctl32.dll) can be deployed locally, skipping the WinSxS. This can be done with the following steps:

    1. Create a folder “Microsoft.Windows.Common-Controls” in deployment exe folder, for example
    MyApp/exe/Microsoft.Windows.Common-Controls

    2. copy comctl32.dll file from C:/WINDOWS/WinSxS/x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.0.0_x-ww_1382d70a folder
    into MyApp/exe/Microsoft.Windows.Common-Controls folder

    3. copy x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.0.0_x-ww_1382d70a.Manifest file from C:/WINDOWS/WinSxS/Manifests folder
    into MyApp/exe/Microsoft.Windows.Common-Controls folder

    4. rename x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.0.0_x-ww_1382d70a.Manifest to Microsoft.Windows.Common-Controls.Manifest

    5. remove publicKeyToken from this new manifest (Microsoft.Windows.Common-Controls.Manifest)

    6. in all dlls and exes manifests remove publicKeyToken from the section described “Microsoft.Windows.Common-Controls”.

    Now comctl32.dll is deployed locally, and WinSxS is bypassed.

    Best regards,
    Svetoslav Kyuchukov

    Eurorisksystems Ltd.
    Varna, BG

  8. Alex Says:

    Thanks for the _BIND_TO_CURRENT_VCLIBS_VERSION tip!

  9. Remington Furman Says:

    Thank you very much for the tip about manually correcting the version in the manifest files. I never would have guessed that they’d ship a bogus manifest with the DLLs.

    Setting version=”9.0.21022.8″ worked perfectly for me.

  10. Gavin Says:

    You are a star, sir. This page has been really helpful. Thankyou.

  11. Gautam Jain Says:

    Fantastic. Thanks.

    _BIND_TO_CURRENT_VCLIBS_VERSION tip worked for me.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值