"由于应用程序配置不正确,应用程序未能启动" VS2008 Release /MD编译

本文详细解析了使用VS2008编译的程序在某些XP系统上因配置问题无法启动的原因,并提供了具体的解决步骤。针对不同版本的VS2008及其补丁情况,给出了相应的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://blog.sina.com.cn/s/blog_48f93b530100ix0a.html

问题描述:
用VS2008 Release /MD模式编译了一个可执行程序,程序依赖的CRT库和对应的manifest文件也都拷贝到了程序所在目录,大部分系统都可以正常打开,但是在一些xp系统上却出现如下对话框:
这里写图片描述

最简单的办法可以安装微软的补丁vcredist_x86.exe(用于WinXP等基于x86平台的系统),该程序会更新系统的应用程序库版本,一般可以解决问题。 但是如果我们想要制作安装包分发程序,或者遇到一些特殊情况,还是要弄清楚问题发生的真正原因,对症下药才行。

首先总结一下“由于应用程序配置不正确,应用程序未能启动”这类问题出现的原因,网上有很多介绍的文章说的很详细,我就直接拿过来用了。
在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文件的内容大致如下:

    <?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处理程序):
在开始菜单里面找到并打开”Visual Studio 2008命令提示”窗口,输入:
mt -inputresource:C:\work\test.exe;#1 /out:C:\work\test.manifest
2、另外一种是使用dumpbin程序将整个exe的内容打印到一个文件,然后用文本编辑器打开,搜索Assem字符串样式就能找到manifest信息:
这里写图片描述

知道了程序依赖于具体哪一个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包安装上就可以了。

根据上面的解释,我们应该大致明白了问题产生的原因以及解决办法。但是有些情况下还是很复杂的,比如我们用VC2008发布release版的程序时,关于库的版本和发布规则有一些注意事项。

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
  帮助-关于Visual Studio,可以看到打了哪些补丁
  打过该补丁后,编译生成的程序的manifest文件里面的版本号是9.0.21022.8,但是Microsoft.VC90.CRT.manifest里面的版本号却是9.0.30729.1。这导致了manifest文件中记录的版本号和实际库的版本号不一致(程序要求它们的版本号一致才能运行)。这个版本的程序部署需要两个步骤,首先要使manifest文件中依赖项的版本号与实际库的版本号一致,均为9.0.21022.8,方法是在工程属性-C/C++-预处理器-预处理器定义里面加一个宏定义_BIND_TO_CURRENT_VCLIBS_VERSION,然后重新编译程序。接下来还是将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就可以在任何机器上直接运行了。
  
另人欣喜的是,VS2010中将不再采用manifest文件,这个产生问题多余解决问题的设计终于可以抛弃了。所以尽快抛弃垃圾的VS2008吧。。

### 如何编译Qt6项目或解决编译问题 #### 编译Qt6项目的流程 为了成功编译Qt6项目,通常需要遵循一系列标准步骤。以下是基于提供的参考资料和常见实践的总结: 1. **设置开发环境** 需要确保已安装必要的依赖项,例如CMake、GCC/Clang/MingW等构建工具以及Python脚本支持。对于Windows平台,推荐使用Visual Studio 2023配合特定版本的MSVC编译器[^2]。 2. **获取源代码** 下载官方发布的Qt6源码包或者通过Git克隆仓库至本地目录。假设目标路径为`C:\Qt\6.5.3\Src`,可以通过批处理文件(如`qt6vars.cmd`)简化变量初始化操作。 3. **配置选项** 使用CMake进行初步配置前,需定义若干参数来指定功能模块启用状态、目标架构类型以及其他定制需求。例如: ```bash cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ -DQT_FEATURE_opengl=no -DQT_FEATURE_vulkan=yes ... ``` 4. **执行实际编译工作** 调用合适的命令启动多线程模式下的完整构建过程。如果采用的是Ninja生成器,则形式如下所示;而传统GNU Makefile则替换相应语法即可。 ```bash cmake --build build --parallel $(nproc) ``` 此外,在某些情况下可能还需要额外关注错误提示信息以便及时调整策略应对潜在障碍[^5]。 --- #### 常见编译问题分析与解决方案 | **现象描述** | **原因剖析** | **建议措施** | |--------------|---------------|----------------| | `event.h: No such file or directory` | 可能缺少libev库头文件及相关动态链接库资源 | 安装对应发行版软件包管理器提供版本 (e.g., Ubuntu下apt-get install libev-dev),确认环境变量PATH包含其位置[^4] | | `'EVP_MD_CTX_cleanup' was not declared in this scope` | OpenSSL API变更引起兼容性冲突 | 升级到最新稳定分支同时查阅迁移指南更新调用方式 | | `Cannot find font directory` | 字体引擎未能正确加载所需字体集 | 明确指明Freetype根目录,并验证相关静态库是否被纳入最终产物清单之中 | 另外值得注意的是关于QML相关内容方面存在专门针对性能优化目的设计出来的两种机制&mdash;&mdash;即分别负责处理JS逻辑片转换成机器指令序列任务(`qmljsc`)以及将自定义UI控件映射成为底层渲染管线可理解结构表示形式的工作流(`qmltc`)。它们共同构成了现代图形界面应用程序高效运行的基础框架体系[^1]。 --- ### 示例代码展示 下面给出一简单的例子演示如何利用上述提到的技术要点完成一个基本窗口显示程序实现: ```cpp #include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; const QString qmlFile(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [quitFunc = [&app]{ app.quit(); }, &engine](QObject* obj, const QUrl& url){ if (!obj && url == qmlFile) quitFunc(); }, Qt::QueuedConnection); engine.load(qmlFile); return app.exec(); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值