2023年11月27日发(作者:)

VS2008编译的程序在某些机器上运行提示“由于应用程序配置不正确,

应用程序未能启动”的问题

VC9编译的程序在没有装过VC9(确切的说是.Net Framework3.5)的机器上运行

时,如果提示“由于应用程序配置不正确,应用程序未能启动。重新安装应用程

序可能会纠正这个问题。”这个错误,那么就说明该程序动态链接了VC9的运行

时库,(如果还用到了MFC,那么可能动态链接了VC9MFC库,同理还有ATL

库),以及缺少对应的manifest文件,程序在目标机器上没有找到这些库和配

置文件,因此导致了这个错误。出现这种情况的VC9编译器可能存在3个版本,

接下来分别阐明:

1、没有打过任何补丁的VS2008

该版本对应的CRT/MFC/ATL库的版本号为9.0.21022.8这个版本号在后面

会用到。这个版本的程序部署比较简单,直接把VC安装目录下的redist目录

C:Program FilesMicrosoft Visual Studio 9.0VCredist)中需要的库以

及对应的manifest文件拷贝到执行程序同目录下,这样程序到任何机器上都能

够正常运行了。

2、打过SP1补丁的VS2008

打过该补丁后,系统中存在着两个版本的CRT/MFC/ATL库,版本号分别为

9.0.21022.89.0.30729.1这导致了manifest文件中记录的版本号和实际库

的版本号不一致(程序要求它们的版本号一致才能运行)这个版本的程序部署

需要两个步骤,首先要使manifest文件中依赖项的版本号与实际库的版本号一

致,均为9.0.30729.1,方法是在工程设置中增加一个宏定义

_BIND_TO_CURRENT_VCLIBS_VERSION,该宏定义于C:Program FilesMicrosoft

Visual Studio 9.0VCincludecrtassem.h文件中,然后重新编译程序。接下

来还是将VC安装目录下的redist目录(C:Program FilesMicrosoft Visual

Studio 9.0VCredist)中需要的库以及对应的manifest文件拷贝到执行程序

同目录下,然后修改manifest文件中依赖项的版本号为9.0.21022.8,这样使

得程序误以为该目录下库的版本号为9.0.21022.8实际上是9.0.30729.1版本)

这样程序到任何机器上都能够正常运行了。

3、打过SP1补丁与SP1 ATL 安全更新 (KB973675)VS2008

这是最新的更新。SP1补丁之后,微软又于近日发布了一个用于智能设备

Microsoft Visual Studio 2008 Service Pack 1 ATL 安全更新 (KB973675)

该补丁又将CRT/MFC/ATL库的版本号升级,为9.0.30729.4148,这次升级比较

好,manifest文件与库的版本号一致了,不像SP1一样升级的不彻底。这样只

需要在工程设置中增加一个宏定义_BIND_TO_CURRENT_VCLIBS_VERSION,接下来

重新编译程序,然后直接把VC安装目录下的redist目录中需要的库以及对应的

manifest文件拷贝到执行程序同目录下,这样程序到任何机器上都能够正常运

行了。

顺便提一下,如果不想在发布程序时带上这些库和manifest文件(如果没

有必要的话),那么可以采用静态编译CRTMFC,然后把manifest文件添加

到资源中,这样编译出的程序只要一个exe就可以在任何机器上直接运行了。

参考文章:

1、“应用程序配置不正确,程序无法启动”的解决方法资料收集:

有的时候,你在Visual C++上面经过好几个月的辛勤努力,终于将程序编

写完成并且测试完毕,然而当你试图在客户的发布机上运行刚写好的程序时,

可能会碰到类似下面的错误,操作系统告诉你“由于应用程序配置不正确,应用

程序未能启动。重新安装应用程序可能会纠正这个问题”.

一般情况下,这个问题都是由于程序不能找到所需要的C运行库(CRT)而

引起的。

Windows XP SP2以后,Windows引入了Side-by-Side执行的概念,这个

概念本来是.NET提出来的,但是Windows后来将这个概念集成到操作系统层面

上来了。大家都应该知道Dll Hell的问题,为了解决Dll Hell的问题,

Side-By-Side提出不同版本的dll文件可以同时存在于同一个系统里面,而且

依赖于不同版本dll的应用程序在运行的时候可以使用到它当初被编译生成的

dll。前面的话,有点绕,举个例子:

1. 假定你编写了一个C++程序A,是使用MFC 8.0(这个版本是随

Visual Studio 2005)发布的。

2. 之后你的机器升级了Visual Studio的版本,从2005升级到

20082008MFC库是9.0版本的,这个时候你的操作系统里面安装了两个版

本的MFC,分别是8.09.0

3. 你在Visual Studio 2008编写了另外一个C++程序BB依赖

MFC 9.0

4. 如果你运行程序A的话,操作系统会将MFC 8.0加载到A的进

程里面。

5. 如果你这时同时运行程序B,操作系统会将MFC 9.0加载到B

的进程里面。这就是Side-by-side的执行概念。

操作系统之所以能够这样做,是因为它在加载程序AB之前,除了查看

PE格式里面AB所依赖的Dll信息,都会查看ABmanifest文件。Manifest

文件保存了Windows可执行文件(包括exedll文件)要运行起来的环境设置

信息,文件名一般是可执行文件的文件全名加上.manifest。例如

manifest文件就应该是st。例外有的程序将manifest

文件直接嵌入到可执行文件的资源里面了,这也就是为什么有的时候你看不到程

序的manifest文件的原因。通常来说,一个manifest文件的内容如下

st文件):

manifestVersion='1.0'>

uiAccess='false' />

name='RT' version='9.0.21022.8'

processorArchitecture='x86'

publicKeyToken='1fc8b3b9a1e18e3b' />

上面的例子里面,就说明这个程序依赖于CRT 9.0,而且是调试版的,CPU

架构是32位的CPU对于将manifest文件嵌入到资源文件的程序我们也有办法

看到manifest的信息。

1. 一种是使用Visual Studio自带的manifest处理程序)

mt -inputresource:;#1 /out:st

2. 另外一种是使用dumpbin程序将整个exe的内容打印到一个文

件,然后用文本编辑器打开,搜索Assem字符串样式就能找到manifest信息:

解决方案

知道了程序依赖于具体哪一个dll以后,你可以将所依赖的dll拷贝到程序

的安装文件夹里面,以CRT库绑定失败为例,介绍解决步骤:

1.从上例中我们知道程序依赖的RT库,版本号是

9.0.21022.8,需要32位机器版本的CRT。这个依赖项一般是因为你的程序是调

试版,所以Visual Studio在编译的时候,将调试版的CRT加入程序的依赖项。

2.Visual Studio的安装文件夹里面将D:"Program Files"Microsoft

Visual Studio 9.0"VC"redist"Debug_NonRedist"x86中的

RT整个文件夹拷贝到应用程序所在的文件夹里面,注意:

a)如果你的程序依赖的是32位的CRT,则要拷贝x86文件夹里面的

RT文件夹,如果是先x64程序,则要拷贝x64文件夹里

面。

b)你需要确定RT文件夹里面的

st文件里面保存的版本信息而你程序依赖的

版本信息匹配,st里面的版本信息大版本号

一定要一致,小版本号一定要等于或者大于你程序依赖的CRT的小版本号。比如

上例中,我们的程序是依赖于CRT 9.0.21022.8,而我们的

st的版本是9.0.30729.1这样是可以的;

8.0.30729.1就会有问题。如果大版本号一样,小版本号不一致的话,一个比较

简单的方案就是修改程序的manifest文件,使其互相匹配就可以了。

3.如果你的程序不是依赖调试版本的CRT,而是release版本的CRT,直接

去微软的官方网站下载一个crt redist包安装上就可以了。

:解决方案参考:

方案一:

方法一:

C:Program FilesMicrosoft Visual Studio 8VCredi

stDebug_RT 下找到了下列文件:

st

把这几个文件拷贝到目标机器上,与运行程序同一文件夹或放到system32下,

就可以运行那个程序了。

其他release,MFC程序什么的都是拷redist下相应文件夹下的文件就可以了,

文件夹后都有标识!

方法二:

修改编译选项,/MD/MDd 改为 /MT/MTd这样就实现了VC运行时库的

静态链接,在运行时就不再需要VCdll了。

方法三:

工程-》属性-》配置属性-》常规-》MFC的使用,选择"在静态库中使用mfc"

这样生成的exe文件应该就可以在其他机器上跑了。

方法四:

你的vc8安装盘上找到再分发包vcredist_和你的程序捆绑安装

我逐一测试下来,直到第三个方法才成功.第二个方法不知道在哪里修改编译选

项所以放弃了,第四个方法不喜欢,这跟直接安装.net framework 2.0 有什么区

别吗?还不如直接安装.net framework 2.0 .

方案二:

最早出现这个错误我和许多人认为的一样

认为是缺乏DLL库文件导致.但是在测试机复制了DLL甚至安装了.net

framework 2.0以后

都无法解决问题,最后确认不是由缺乏DLL所致

因为程序是纯win32的应用程,非托管代码,所以也无需.net framework

Visual C++2003/2005默认的MFC程序是使用动态MFC(Use MFC in a Shared

DLL)来链接的

而动态MFC库使用的是Multi-threaded DLL (/MD)

由于XP对于PE文件格式监测更加严格.

就会导致部分使用多线程DLL的可执行文件在调用的时候出错

修改项目属性的编译开关

Project->Property->configuration Properties->C/C++->Code

Generation->Runtime Library

修改成Multi-threaded (/MT)

修改了Runtime类型以后

需要将MFC的编译类型也改成静态库

Project->Property->configuration Properties->General->Use of MFC

修改成Use MFC in a Static Library

一部分情况下在这步就能解决问题

另外一部分情况会遇见如下情况

编译器报错

CODE:

() : error LNK2005: "void * __cdecl operator

new[](unsigned int)" (??_U@YAPAXI@Z) already defined in

()

[Copy to clipboard]

产生这个问题的原因是库依赖关系

Project->Property->configuration Properties->Linker->Command Line

加入编译开关/verbose:lib可以显示详细的库链接顺序

CODE:

------ Build started: Project: PerfMonDemo, Configuration: Release Win32

------

Searching libraries

Searching d:Program FilesMicrosoft Visual Studio

:

Searching d:Program FilesMicrosoft Visual Studio

:

.................

Searching d:Program FilesMicrosoft Visual Studio

:

Finished searching libraries

.Release/ : fatal error LNK1169: one or more multiply

而是在最后在加入对他们的引用.这样就避免了这个问题

下面是一张可能发生冲突的列表

若要使用此运行时库 请忽略这些库

单线程 ()

多线程 ()

使用 DLL 的多线程 ()

调试单线程 ()

调试多线程 ()

使用 DLL 的调试多线程 ()