C++ 应用程序不能与 VS 2008 SP1 DLL 一起运行,以前的版本适用于 RTM 版本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/59635/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
App does not run with VS 2008 SP1 DLLs, previous version works with RTM versions
提问by crashmstr
Since our switch from Visual Studio 6 to Visual Studio 2008, we've been using the MFC90.dll and msvc[pr]90.dlls along with the manifest files in a private side-by-side configuration so as to not worry about versions or installing them to the system.
自从我们从 Visual Studio 6 切换到 Visual Studio 2008 以来,我们一直在使用 MFC90.dll 和 msvc[pr]90.dll 以及私有并行配置中的清单文件,以免担心版本或将它们安装到系统中。
Pre-SP1, this was working fine (and still works fine on our developer machines). Now that we've done some testing post-SP1 I've been pulling my hair out since yesterday morning.
在 SP1 之前,这运行良好(并且在我们的开发人员机器上仍然运行良好)。现在我们已经在 SP1 之后做了一些测试,我从昨天早上开始就一直在拔头发。
First off, our NSIS installer script pulls the dlls and manifest files from the redist folder. These were no longer correct, as the app still links to the RTM version.
首先,我们的 NSIS 安装程序脚本从 redist 文件夹中提取 dll 和清单文件。这些不再正确,因为应用程序仍然链接到 RTM 版本。
So I added the define for _BIND_TO_CURRENT_VCLIBS_VERSION=1
to all of our projects so that they will use the SP1 DLLs in the redist folder (or subsequent ones as new service packs come out). It took me hours to find this.
所以我为_BIND_TO_CURRENT_VCLIBS_VERSION=1
我们所有的项目添加了定义,以便他们将使用 redist 文件夹中的 SP1 DLL(或随着新服务包的出现而使用后续的)。我花了几个小时才找到这个。
I've double checked the generated manifest files in the intermediate files folder from the compilation, and they correctly list the 9.0.30729.1 SP1 versions. I've double and triple checked depends on a clean machine: it all links to the local dlls with no errors.
我已经仔细检查了编译的中间文件文件夹中生成的清单文件,它们正确地列出了 9.0.30729.1 SP1 版本。我已经两次和三次检查取决于一台干净的机器:它所有链接到本地 dll 都没有错误。
Running the app still gets the following error:
运行应用程序仍然出现以下错误:
The application failed to initialize properly (0xc0150002). Click on OK to terminate the application.
应用程序未能正确初始化 (0xc0150002)。单击“确定”终止应用程序。
None of the searches I've done on google or microsoft have come up with anything that relates to my specific issues (but there are hits back to 2005 with this error message).
我在 google 或 microsoft 上所做的任何搜索都没有提出与我的特定问题相关的任何内容(但此错误消息可以追溯到 2005 年)。
Any one had any similar problem with SP1?
有没有人在 SP1 上遇到过类似的问题?
Options:
选项:
- Find the problem and fix it so it works as it should (preferred)
- Install the redist
- dig out the old RTM dlls and manifest files and remove the #define to use the current ones. (I've got them in an earlier installer build, since Microsoft blasts them out of your redist folder!)
- 找到问题并修复它,使其正常工作(首选)
- 安装 redist
- 挖掘旧的 RTM dll 和清单文件并删除 #define 以使用当前的。(我在较早的安装程序版本中安装了它们,因为 Microsoft 将它们从您的 redist 文件夹中删除了!)
Edit:I've tried re-building with the define turned off (link to RTM dlls), and that works as long as the RTM dlls are installed in the folder. If the SP1 dlls are dropped in, it gets the following error:
编辑:我尝试在关闭定义的情况下重新构建(链接到 RTM dll),只要 RTM dll 安装在文件夹中,它就可以工作。如果放入 SP1 dll,则会出现以下错误:
c:\Program Files\...\...\X.exe
This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.
c:\Program Files\...\...\X.exe
此应用程序无法启动,因为应用程序配置不正确。重新安装应用程序可能会解决此问题。
Has no-one else had to deal with this issue?
没有其他人需要处理这个问题吗?
Edit:Just for grins, I downloaded and ran the vcredist_x86.exe for VS2008SP1 on my test machine. Itworks. With the SP1 DLLs. And my RTM linked app. But NOTin a private side-by-side distribution that worked pre-SP1.
编辑:只是为了咧嘴笑,我在我的测试机器上下载并运行了用于 VS2008SP1 的 vcredist_x86.exe。它有效。使用 SP1 DLL。还有我的 RTM 链接应用程序。但不是在 SP1 之前运行的私有并行分发中。
回答by Roel
I have battled this problem myself last week and consider myself somewhat of an expert now ;)
上周我自己解决了这个问题,现在认为自己有点专家;)
I'm 99% sure that not all dlls and static libraries were recompiled with the SP1 version. You need to put
我 99% 确定并非所有 dll 和静态库都使用 SP1 版本重新编译。你需要把
#define _BIND_TO_CURRENT_MFC_VERSION 1
#define _BIND_TO_CURRENT_CRT_VERSION 1
into everyproject you're using. For every project of a real-world size, it's very easy to forget some small lib that wasn't recompiled.
到您正在使用的每个项目中。对于每个实际大小的项目,很容易忘记一些没有重新编译的小库。
There are more flags that define what versions to bind to; it's documented on http://msdn.microsoft.com/en-us/library/cc664727%28v=vs.90%29.aspx. As an alternative to the lines above, you can also put
还有更多的标志来定义要绑定到的版本;它记录在http://msdn.microsoft.com/en-us/library/cc664727%28v=vs.90%29.aspx 上。作为上述行的替代,您还可以将
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1
which will bind to the latest version of all VC libs (CRT, MFC, ATL, OpenMP).
它将绑定到所有 VC 库(CRT、MFC、ATL、OpenMP)的最新版本。
Then, check what the embedded manifest says. Download XM Resource Editor: http://www.wilsonc.demon.co.uk/d10resourceeditor.htm. Open every dll and exe in your solution. Look under 'XP Theme Manifest'. Check that the 'version' attribute on the right-hand side is '9.0.30729.1'. If it's '9.0.21022', some static library is pulling in the manifest for the old version.
然后,检查嵌入式清单的内容。下载 XM 资源编辑器:http: //www.wilsonc.demon.co.uk/d10resourceeditor.htm。打开解决方案中的每个 dll 和 exe。在“XP 主题清单”下查看。检查右侧的“版本”属性是否为“9.0.30729.1”。如果它是“9.0.21022”,则一些静态库正在拉入旧版本的清单。
What I found is that in many cases, bothversions were included in the manifest. This means that some libraries use the sp1 version and others don't.
我发现在许多情况下,这两个版本都包含在清单中。这意味着某些库使用 sp1 版本而其他库不使用。
A great way to debug which libraries don't have the preprocessor directives set: temporarily modify your platform headers so that compilation stops when it tries to embed the old manifest. Open C:\Program Files\Microsoft Visual Studio 9.0\VC\crt\include\crtassem.h. Search for the '21022' string. In that define, put something invalid (change 'define' to 'blehbleh' or so). This way, when you're compiling a project where the _BIND_TO_CURRENT_CRT_VERSION
preprocessor flag is not set, your compilation will stop and you'll know that you need to add them or made sure that it's applied everywhere.
调试哪些库没有设置预处理器指令的好方法:临时修改平台标头,以便在尝试嵌入旧清单时停止编译。打开 C:\Program Files\Microsoft Visual Studio 9.0\VC\crt\include\crtassem.h。搜索“21022”字符串。在那个定义中,放一些无效的东西(将“定义”更改为“blehbleh”左右)。这样,当您编译_BIND_TO_CURRENT_CRT_VERSION
未设置预处理器标志的项目时,您的编译将停止,您将知道需要添加它们或确保它在任何地方应用。
Also make sure to use Dependency Walker so that you know what dlls are being pulled in. It's easiest to install a fresh Windows XP copy with no updates (only SP2) on a virtual machine. This way you know for sure that there is nothing in the SxS folder that is being used instead of the side-by-side dlls that you supplied.
还要确保使用 Dependency Walker,以便您知道正在拉入哪些 dll。最简单的方法是在虚拟机上安装没有更新的全新 Windows XP 副本(仅 SP2)。通过这种方式,您可以确定正在使用的 SxS 文件夹中没有任何内容,而不是您提供的并排 dll。
回答by Dimitri C.
To understand the problem, I think it is important to realize that there are four version numbers involved:
要理解这个问题,我认为重要的是要意识到涉及四个版本号:
- (A) The version of the VC header files to which the .exe is compiled.
- (B) The version of the manifest file that is embedded in the resources section of that .exe. By default, this manifest file is automatically generated by Visual Studio.
- (C) The version of the VC .DLLs (part of the side-by-side assembly) you copy in the same directory as the .exe.
- (D) The version of the VC manifest files (part of the side-by-side assembly) you copy in the same directory as the .exe.
- (A) .exe 编译成的 VC 头文件的版本。
- (B) 嵌入在该 .exe 的资源部分中的清单文件的版本。默认情况下,此清单文件由 Visual Studio 自动生成。
- (C) 您在与 .exe 相同的目录中复制的 VC .DLL(并行程序集的一部分)的版本。
- (D) 您在与 .exe 相同的目录中复制的 VC 清单文件(并行程序集的一部分)的版本。
There are two versions of the VC 2008 DLL's in the running:
有两个版本的 VC 2008 DLL 正在运行:
- v1: 9.0.21022.8
- v2: 9.0.30729.4148
- v1:9.0.21022.8
- v2:9.0.30729.4148
For clarity, I'll use the v1/v2 notation. The following table shows a number of possible situations:
为清楚起见,我将使用 v1/v2 表示法。下表显示了多种可能的情况:
Situation | .exe (A) | embedded manifest (B) | VC DLLs (C) | VC manifests (D)
-----------------------------------------------------------------------------
1 | v2 | v1 | v1 | v1
2 | v2 | v1 | v2 | v2
3 | v2 | v1 | v2 | v1
4 | v2 | v2 | v2 | v2
The results of these situations when running the .exe on a clean Vista SP1 installation are:
在干净的 Vista SP1 安装上运行 .exe 时,这些情况的结果是:
Situation 1: a popup is shown, saying: "The procedure entry point XYZXYZ could not be located in the dynamic link library".
Situation 2: nothing seems to happen when running the .exe, but the following event is logged in Windows' "Event Viewer / Application log":
Activation context generation failed for "C:\Path\file.exe".Error in manifest or policy file "C:\Path\Microsoft.VC90.CRT.MANIFEST" on line 4. Component identity found in manifest does not match the identity of the component requested. Reference is Microsoft.VC90.CRT,processorArchitecture="x86",publicKeyToken="1fc8b3b9a1e18e3b",type="win32",version="9.0.21022.8". Definition is Microsoft
Situation 3: everything seems to work fine. This is remicles2's solution.
Situation 4: this is how it should be done. Regrettably, as Roel indicates, it can be rather hard to implement.
情况1:显示一个弹出窗口,说:“在动态链接库中找不到过程入口点XYZXYZ”。
情况 2:运行 .exe 时似乎没有任何反应,但 Windows 的“事件查看器/应用程序日志”中记录了以下事件:
“C:\Path\file.exe”的激活上下文生成失败。清单或策略文件“C:\Path\Microsoft.VC90.CRT.MANIFEST”中的第 4 行错误。在清单中找到的组件标识与标识不匹配请求的组件。参考是 Microsoft.VC90.CRT,processorArchitecture="x86",publicKeyToken="1fc8b3b9a1e18e3b",type="win32",version="9.0.21022.8"。定义是微软
情况 3:一切似乎都正常。这是remicles2 的解决方案。
情况 4:这是应该如何做的。遗憾的是,正如 Roel 指出的那样,它可能很难实施。
Now, my situation (and I think it is the same as crashmstr's) is nr 1. The problem is that Visual Studio for one reason or another generates client code (A) for v2, but for one reason or another, generates a v1 manifest file (B). I have no idea where version (A) can be configured.
现在,我的情况(我认为它与crashmstr 的情况相同)是 nr 1。问题是 Visual Studio 出于某种原因或另一种原因为 v2 生成客户端代码 (A),但出于某种原因,生成了 v1 清单文件 (B)。我不知道在哪里可以配置版本 (A)。
Notethat this whole explanation is still in the context of private assemblies.
请注意,整个解释仍在私有程序集的上下文中。
Update: finally I start to understand what is going on. Apparently, Visual Studio generates client code (A) for v2 by default, contrary to what I've read on some Microsoft blogs. The _BIND_TO_CURRENT_VCLIBS_VERSION flag only selects the version in the generated manifest file (B), but this version will be ignored when running the application.
更新:终于我开始明白发生了什么。显然,Visual Studio 默认为 v2 生成客户端代码 (A),这与我在一些 Microsoft 博客上读到的相反。_BIND_TO_CURRENT_VCLIBS_VERSION 标志仅选择生成的清单文件 (B) 中的版本,但在运行应用程序时将忽略此版本。
Conclusion
结论
An .exe that is compiled by Visual Studio 2008 links to the newest versions of the VC90 DLLs by default. You can use the _BIND_TO_CURRENT_VCLIBS_VERSION flagto control which version of the VC90 libraries will be generated in the manifest file. This indeed avoids situation 2 where you get the error message "manifest does not match the identity of the component requested". It also explains why situation 3 works fine, as even without the _BIND_TO_CURRENT_VCLIBS_VERSION flag the application is linked to the newest versions of the VC DLLs.
默认情况下,由 Visual Studio 2008 编译的 .exe 链接到最新版本的 VC90 DLL。您可以使用 _BIND_TO_CURRENT_VCLIBS_VERSION 标志来控制将在清单文件中生成哪个版本的 VC90 库。这确实避免了出现错误消息“清单与请求的组件的身份不匹配”的情况 2。它还解释了为什么情况 3 工作正常,因为即使没有 _BIND_TO_CURRENT_VCLIBS_VERSION 标志,应用程序也会链接到最新版本的 VC DLL。
The situation is even weirder with public side-by-side assemblies, where vcredist was run, putting the VC 9.0 DLLs in the Windows SxS directory. Even if the .exe's manifest file states that the old versions of the DLLs should be used (this is the case when the _BIND_TO_CURRENT_VCLIBS_VERSION flag is not set), Windows ignoresthis version number by default! Instead, Windows will use a newer version if present on the system, except when an "application configuration file"is used.
对于运行 vcredist 的公共并行程序集,情况甚至更奇怪,将 VC 9.0 DLL 放在 Windows SxS 目录中。即使 .exe 的清单文件指出应使用旧版本的 DLL(这是未设置 _BIND_TO_CURRENT_VCLIBS_VERSION 标志时的情况),Windows 也会默认忽略此版本号!相反,Windows 将使用系统上存在的较新版本,除非使用“应用程序配置文件”。
Am I the only one who thinks this is confusing?
我是唯一一个认为这很混乱的人吗?
So in summary:
所以总结一下:
- For private assemblies, use the _BIND_TO_CURRENT_VCLIBS_VERSION flag in the .exe's project and alldependent .lib projects.
- For public assemblies, this is not required, as Windows will automatically select the correct version of the .DLLs from the SxS directory.
- 对于私有程序集,请在 .exe 的项目和所有依赖的 .lib 项目中使用 _BIND_TO_CURRENT_VCLIBS_VERSION 标志。
- 对于公共程序集,这不是必需的,因为 Windows 会自动从 SxS 目录中选择正确版本的 .DLL。
回答by remcycles
Another nice tool for viewing exe and dll manifests is Manifest View, which fittingly enough will not run on a clean install of XP, because itdepends on 9.0.21022.
另一个用于查看 exe 和 dll 清单的好工具是Manifest View,它不会在全新安装的 XP 上运行,因为它依赖于 9.0.21022。
回答by Roel
I just remembered another trick that I used to find out which static libraries were ill-behaving: 'grep' through the static libraries for the string '21022'. HOWEVER, don't use the 'normal' grep tools like wingrep because they won't show you these strings (they think it's a binary file and look for the raw, non-unicode string). Use the 'strings' utility from the resource kit (now in the Russinovich site I think). That one will grep through binaries ok. So you let this 'strings' go through your whole source tree and you'll see the binary files (dlls and static libraries) that contain references to the wrong manifest (or to the manifest with the wrong version in it).
我只记得我用来找出哪些静态库表现不佳的另一个技巧:通过字符串“21022”的静态库的“grep”。但是,不要使用像 wingrep 这样的“普通”grep 工具,因为它们不会向您显示这些字符串(他们认为这是一个二进制文件并查找原始的非 unicode 字符串)。使用资源工具包中的“字符串”实用程序(我认为现在在 Russinovich 站点中)。那个将通过二进制文件grep ok。因此,您让这个“字符串”遍历整个源代码树,您将看到二进制文件(dll 和静态库),其中包含对错误清单(或包含错误版本的清单)的引用。
回答by remcycles
For your third option, you can probably find the DLLs and manifests for the 9.0.21022 version in the C:\WINDOWS\WinSxS directory on your dev machine. If you can, then you can setup your own redist directory and install those files with your app.
对于第三个选项,您可能可以在开发机器上的 C:\WINDOWS\WinSxS 目录中找到 9.0.21022 版本的 DLL 和清单。如果可以,那么您可以设置自己的 redist 目录并使用您的应用程序安装这些文件。
Alternatively, you can use the 9.0.30729.1 ones supplied with Visual Studio and forge the manifest you install with your app to report that it supplies the 9.0.21022 DLLs, and not 9.0.30729.1. The runtime linker doesn't seem to mind. See this blog, which has been immensely helpful for solving these problems, for more information.
或者,您可以使用 Visual Studio 提供的 9.0.30729.1 并伪造与应用一起安装的清单,以报告它提供 9.0.21022 DLL,而不是 9.0.30729.1。运行时链接器似乎并不介意。有关更多信息,请参阅此博客,它对解决这些问题非常有帮助。
Both workarounds fixed the problems I had with deploying the DLLs as private assemblies with VS2008 Express.
两种解决方法都解决了我在使用 VS2008 Express 将 DLL 部署为私有程序集时遇到的问题。
Roel's answer is the way to go for your first option ("fix it right"), but if you depend on a library that depends on 9.0.21022 (and your manifest therefore lists both versions), then the third option may be the only way to go if you don't want to run vcredist_x86.exe.
Roel 的答案是您的第一个选项(“正确修复”),但如果您依赖于依赖 9.0.21022 的库(因此您的清单列出了两个版本),那么第三个选项可能是唯一的如果您不想运行 vcredist_x86.exe,可以采用以下方法。