• VS2008编译的程序在某些机器上运行提示“由于应用程序配置不正确,应用程序未能启动”的问题(转)


    VC9编译的程序在没有装过VC9(确切的说是.Net Framework3.5)的机器上运行时,如果提示“由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题。”这个错误,那么就说明该程序动态链接了VC9的运行时库,(如果还用到了MFC,那么可能动态链接了VC9的MFC库,同理还有ATL库),以及缺少对应的manifest文件,程序在目标机器上没有找到这些库和配置文件,因此导致了这个错误。出现这种情况的VC9编译器可能存在3个版本,接下来分别阐明:

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

    该版本对应的CRT/MFC/ATL库的版本号为9.0.21022.8,这个版本号在后面会用到。这个版本的程序部署比较简单,直接把VC安装目录下的redist目录(C:\Program Files\Microsoft Visual Studio 9.0\VC\redist)中需要的库以及对应的manifest文件拷贝到执行程序同目录下,这样程序到任何机器上都能够正常运行了。

    2、打过SP1补丁的VS2008

    打过该补丁后,系统中存在着两个版本的CRT/MFC/ATL库,版本号分别为9.0.21022.8和9.0.30729.1,这导致了manifest文件中记录的版本号和实际库的版本号不一致(程序要求它们的版本号一致才能运行)。这个版本的程序部署需要两个步骤,首先要使manifest文件中依赖项的版本号与实际库的版本号一致,均为9.0.30729.1,方法是在工程设置中增加一个宏定义_BIND_TO_CURRENT_VCLIBS_VERSION,该宏定义于C:\Program Files\Microsoft Visual Studio 9.0\VC\include\crtassem.h文件中,然后重新编译程序。接下来还是将VC安装目录下的redist目录(C:\Program Files\Microsoft Visual Studio 9.0\VC\redist)中需要的库以及对应的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文件(如果没有必要的话),那么可以采用静态编译CRT和MFC,然后把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升级到2008,2008的MFC库是9.0版本的,这个时候你的操作系统里面安装了两个版本的MFC,分别是8.0和9.0。

    3.         你在Visual Studio 2008编写了另外一个C++程序B,B依赖与MFC 9.0。

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

    5.         如果你这时同时运行程序B,操作系统会将MFC 9.0加载到B的进程里面。这就是Side-by-side的执行概念。

     

    操作系统之所以能够这样做,是因为它在加载程序A和B之前,除了查看PE格式里面A和B所依赖的Dll信息,都会查看A和B的manifest文件。Manifest文件保存了Windows可执行文件(包括exe和dll文件)要运行起来的环境设置信息,文件名一般是可执行文件的文件全名加上.manifest。例如notepad.exe的manifest文件就应该是notepad.exe.manifest。例外有的程序将manifest文件直接嵌入到可执行文件的资源里面了,这也就是为什么有的时候你看不到程序的manifest文件的原因。通常来说,一个manifest文件的内容如下(test.exe.manifest文件):

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

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

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

        <security>

          <requestedPrivileges>

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

          </requestedPrivileges>

        </security>

    </trustInfo>

    <dependency>

        <dependentAssembly>

          <assemblyIdentity type='win32' name='Microsoft.VC90.DebugCRT' version='9.0.21022.8'

                            processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />

        </dependentAssembly>

    </dependency>

    </assembly>

    上面的例子里面,就说明这个程序依赖于CRT 9.0,而且是调试版的,CPU架构是32位的CPU。对于将manifest文件嵌入到资源文件的程序我们也有办法看到manifest的信息。

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

    mt -inputresource:test.exe;#1 /out:test.manifest

    2.         另外一种是使用dumpbin程序将整个exe的内容打印到一个文件,然后用文本编辑器打开,搜索Assem字符串样式就能找到manifest信息:

    VS2008编译的程序在某些机器上运行提示“由于应用程序配置不正确,应用程序未能启动”的问题 - tangxingqt - doomgnu的博客

    解决方案

    知道了程序依赖于具体哪一个dll以后,你可以将所依赖的dll拷贝到程序的安装文件夹里面,以CRT库绑定失败为例,介绍解决步骤:

    1.从上例中我们知道程序依赖的Microsoft.VC90.DebugCRT库,版本号是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中的Microsoft.VC90.DebugCRT整个文件夹拷贝到应用程序所在的文件夹里面,注意:

    a)如果你的程序依赖的是32位的CRT,则要拷贝x86文件夹里面的Microsoft.VC90.DebugCRT文件夹,如果是先x64程序,则要拷贝x64文件夹里面。

    b)你需要确定Microsoft.VC90.DebugCRT文件夹里面的Microsoft.VC90.DebugCRT.manifest文件里面保存的版本信息而你程序依赖的版本信息匹配,Microsoft.VC90.DebugCRT.manifest里面的版本信息大版本号一定要一致,小版本号一定要等于或者大于你程序依赖的CRT的小版本号。比如上例中,我们的程序是依赖于CRT 9.0.21022.8,而我们的Microsoft.VC90.DebugCRT.manifest的版本是9.0.30729.1,这样是可以的;而8.0.30729.1就会有问题。如果大版本号一样,小版本号不一致的话,一个比较简单的方案就是修改程序的manifest文件,使其互相匹配就可以了。

    3.如果你的程序不是依赖调试版本的CRT,而是release版本的CRT,直接去微软的官方网站下载一个crt redist包安装上就可以了。

     

    附:解决方案参考:

    方案一:


    方法一:
    在C:\Program Files\Microsoft Visual Studio 8\VC\redi
    st\Debug_NonRedist\x86\Microsoft.VC80.DebugCRT 下找到了下列文件:

    msvcm80d.dll
    msvcp80d.dll
    msvcr80d.dll
    Microsoft.VC80.DebugCRT.manifest

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

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

    方法二:
    修改编译选项,将/MD或/MDd 改为 /MT或/MTd,这样就实现了对VC运行时库的静态链接,在运行时就不再需要VC的dll了。

    方法三:

    工程-》属性-》配置属性-》常规-》MFC的使用,选择"在静态库中使用mfc"
    这样生成的exe文件应该就可以在其他机器上跑了。

    方法四:

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

    我逐一测试下来,直到第三个方法才成功.第二个方法不知道在哪里修改编译选项所以放弃了,第四个方法不喜欢,这跟直接安装.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:
    nafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new[](unsigned int)" (??_U@YAPAXI@Z) already defined in libcpmt.lib(newaop.obj)
    [Copy to clipboard]


    产生这个问题的原因是库依赖关系
    在Project->Property->configuration Properties->Linker->Command Line
    加入编译开关/verbose:lib可以显示详细的库链接顺序
    CODE:

    ------ Build started: Project: PerfMonDemo, Configuration: Release Win32 ------
    Linking...
    Searching libraries
    Searching d:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\lib\pdh.lib:
    Searching d:\Program Files\Microsoft Visual Studio 8\VC\lib\DelayImp.lib:
    .................
    Searching d:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\lib\nafxcw.lib:
    Finished searching libraries
    .\Release/PerfMonDemo.exe : fatal error LNK1169: one or more multiply defined symbols found
    Build log was saved at "file://d:\Dev\Performance Monitor\Release\BuildLog.htm"
    PerfMonDemo - 2 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

    [Copy to clipboard]

    我们发现在libcpmt.lib声明过的operator new在nafxcw.lib中再次定义
    解决方法如下
    Project->Property->configuration Properties->Linker->Input->Additional Dependencies
    加入
    nafxcw.lib
    libcpmt.lib
    Project->Property->configuration Properties->Linker->Input->Ignore Specific Library
    加入
    nafxcw.lib
    libcpmt.lib
    这样链接程序就不会先按照默认顺序来连接这两个库文件
    而是在最后在加入对他们的引用.这样就避免了这个问题
    下面是一张可能发生冲突的列表
    若要使用此运行时库 请忽略这些库
    单线程 (libc.lib) libcmt.lib、msvcrt.lib、libcd.lib、libcmtd.lib、msvcrtd.lib
    多线程 (libcmt.lib) libc.lib、msvcrt.lib、libcd.lib、libcmtd.lib、msvcrtd.lib
    使用 DLL 的多线程 (msvcrt.lib) libc.lib、libcmt.lib、libcd.lib、libcmtd.lib、msvcrtd.lib
    调试单线程 (libcd.lib) libc.lib、libcmt.lib、msvcrt.lib、libcmtd.lib、msvcrtd.lib
    调试多线程 (libcmtd.lib) libc.lib、libcmt.lib、msvcrt.lib、libcd.lib、msvcrtd.lib
    使用 DLL 的调试多线程 (msvcrtd.lib) libc.lib、libcmt.lib、msvcrt.lib、libcd.lib、libcmtd.lib

  • 相关阅读:
    XAML学习笔记之Layout(五)——ViewBox
    XAML学习笔记——Layout(三)
    XAML学习笔记——Layout(二)
    XAML学习笔记——Layout(一)
    从0开始搭建SQL Server 2012 AlwaysOn 第三篇(安装数据,配置AlwaysOn)
    从0开始搭建SQL Server 2012 AlwaysOn 第二篇(配置故障转移集群)
    从0开始搭建SQL Server 2012 AlwaysOn 第一篇(AD域与DNS)
    Sql Server 2012 事务复制遇到的问题及解决方式
    Sql Server 2008R2升级 Sql Server 2012 问题
    第一次ACM
  • 原文地址:https://www.cnblogs.com/cumtb3S/p/1748069.html
Copyright © 2020-2023  润新知