37

自从我们从 Visual Studio 6 切换到 Visual Studio 2008 以来,我们一直在使用 MFC90.dll 和 msvc[pr]90.dll 以及私有并排配置中的清单文件,以免担心版本或将它们安装到系统中。

在 SP1 之前,它运行良好(在我们的开发人员机器上仍然运行良好)。既然我们已经在 SP1 后进行了一些测试,我从昨天早上开始就一直在拔头发。

首先,我们的 NSIS 安装程序脚本从 redist 文件夹中提取 dll 和清单文件。这些不再正确,因为该应用程序仍链接到 RTM 版本。

因此,我将定义添加_BIND_TO_CURRENT_VCLIBS_VERSION=1到我们所有的项目中,以便他们将使用 redist 文件夹中的 SP1 DLL(或在新服务包出现时使用后续的)。我花了几个小时才找到这个。

我已经从编译中仔细检查了中间文件文件夹中生成的清单文件,它们正确列出了 9.0.30729.1 SP1 版本。我已经两次和三次检查取决于一台干净的机器:它都链接到本地​​ dll,没有错误。

运行应用程序仍然会出现以下错误:

应用程序未能正确初始化 (0xc0150002)。单击确定以终止应用程序。

我在 google 或 microsoft 上进行的搜索都没有找到与我的具体问题相关的任何内容(但有回溯到 2005 年的此错误消息)。

有人对 SP1 有过类似的问题吗?

选项:

  • 找到问题并修复它,使其正常工作(首选)
  • 安装redist
  • 挖出旧的 RTM dll 和清单文件并删除 #define 以使用当前的。(我在较早的安装程序版本中得到了它们,因为 Microsoft 将它们从您的 redist 文件夹中删除!)

编辑:我尝试在关闭定义的情况下重新构建(链接到 RTM dll),只要 RTM dll 安装在文件夹中,它就可以工作。如果将 SP1 dll 放入,则会收到以下错误:

c:\Program Files\...\...\X.exe

此应用程序无法启动,因为应用程序配置不正确。重新安装应用程序可能会解决此问题。

没有其他人必须处理这个问题吗?

编辑:只是为了笑,我在我的测试机器上下载并运行了 VS2008SP1 的 vcredist_x86.exe。有效。使用 SP1 DLL。还有我的 RTM 链接应用程序。但不是在 SP1 之前工作的私有并行分发中。

4

5 回答 5

40

上周我自己也解决了这个问题,现在我认为自己有点专家了;)

我 99% 确定并非所有 dll 和静态库都使用 SP1 版本重新编译。你需要把

#define _BIND_TO_CURRENT_MFC_VERSION 1
#define _BIND_TO_CURRENT_CRT_VERSION 1

进入您正在使用的每个项目。对于每个实际大小的项目,很容易忘记一些没有重新编译的小库。

还有更多的标志来定义要绑定的版本;它记录在http://msdn.microsoft.com/en-us/library/cc664727%28v=vs.90%29.aspx上。作为上述行的替代方案,您还可以将

#define _BIND_TO_CURRENT_VCLIBS_VERSION 1

它将绑定到所有 VC 库(CRT、MFC、ATL、OpenMP)的最新版本。

然后,检查嵌入式清单的内容。下载 XM 资源编辑器:http: //www.wilsonc.demon.co.uk/d10resourceeditor.htm。打开解决方案中的每个 dll 和 exe。查看“XP 主题清单”。检查右侧的“版本”属性是否为“9.0.30729.1”。如果是“9.0.21022”,则某些静态库正在拉入旧版本的清单。

我发现,在许多情况下,这两个版本都包含在清单中。这意味着一些库使用 sp1 版本而其他库不使用。

调试哪些库没有设置预处理器指令的好方法:临时修改平台头文件,以便在尝试嵌入旧清单时停止编译。打开 C:\Program Files\Microsoft Visual Studio 9.0\VC\crt\include\crtassem.h。搜索“21022”字符串。在该定义中,放置一些无效的内容(将“定义”更改为“blehbleh”左右)。这样,当您编译一个_BIND_TO_CURRENT_CRT_VERSION未设置预处理器标志的项目时,您的编译将停止,您将知道您需要添加它们或确保它适用于任何地方。

还要确保使用 Dependency Walker,这样您就知道要提取哪些 dll。在虚拟机上安装没有更新(仅 SP2)的全新 Windows XP 副本是最简单的。通过这种方式,您可以确定 SxS 文件夹中没有任何内容正在使用,而不是您提供的并排 dll。

于 2008-09-16T09:47:15.053 回答
14

要理解这个问题,我认为重要的是要意识到涉及四个版本号

  • (A) .exe 编译到的 VC 头文件的版本。
  • (B) 该 .exe 的资源部分中嵌入的清单文件的版本。默认情况下,此清单文件由 Visual Studio 自动生成。
  • (C) 您复制到与 .exe 相同的目录中的 VC .DLL(并行程序集的一部分)的版本。
  • (D) 您复制到与 .exe 相同的目录中的 VC 清单文件(并行程序集的一部分)的版本。

有两个版本的 VC 2008 DLL 正在运行:

  • v1:9.0.21022.8
  • v2:9.0.30729.4148

为清楚起见,我将使用 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

在干净的 Vista SP1 安装上运行 .exe 时,这些情况的结果是:

  • 情况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 所指出的,实施起来可能相当困难。

现在,我的情况(我认为它与crashmstr's相同)是 nr 1。问题是 Visual Studio 出于某种原因为 v2 生成客户端代码 (A),但出于某种原因,生成了 v1 清单文件 (B)。我不知道可以在哪里配置版本 (A)。

请注意,这整个解释仍然是在私有程序集的上下文中。

更新:终于我开始明白发生了什么。显然,Visual Studio 默认为 v2 生成客户端代码 (A),这与我在一些 Microsoft 博客上读到的相反。_BIND_TO_CURRENT_VCLIBS_VERSION 标志只选择生成的清单文件 (B) 中的版本,但在运行应用程序时会忽略此版本。

结论

默认情况下,由 Visual Studio 2008 编译的 .exe 链接到最新版本的 VC90 DLL。您可以使用 _BIND_TO_CURRENT_VCLIBS_VERSION 标志来控制将在清单文件中生成哪个版本的 VC90 库。这确实避免了您收到错误消息“清单与请求的组件的身份不匹配”的情况 2。它还解释了为什么情况 3 工作正常,因为即使没有 _BIND_TO_CURRENT_VCLIBS_VERSION 标志,应用程序也链接到最新版本的 VC DLL。

对于运行 vcredist 并将 VC 9.0 DLL 放在 Windows SxS 目录中的公共并行程序集,情况就更加奇怪了。即使 .exe 的清单文件声明应使用旧版本的 DLL(这是未设置 _BIND_TO_CURRENT_VCLIBS_VERSION 标志的情况),Windows默认忽略此版本号!相反,Windows 将使用系统上存在的较新版本,除非使用“应用程序配置文件”

我是唯一一个认为这很混乱的人吗?

总而言之:_

  • 对于私有程序集,请在 .exe 的项目和所有依赖的 .lib 项目中使用 _BIND_TO_CURRENT_VCLIBS_VERSION 标志。
  • 对于公共程序集,这不是必需的,因为 Windows 会自动从 SxS 目录中选择正确版本的 .DLL。
于 2010-01-28T08:06:02.030 回答
4

我只记得我用来找出哪些静态库行为不端的另一个技巧:通过字符串“21022”的静态库进行“grep”。但是,不要使用像wingrep 这样的“普通” grep 工具,因为它们不会向您显示这些字符串(他们认为这是一个二进制文件并查找原始的非Unicode 字符串)。使用资源工具包中的“字符串”实用程序(我认为现在在 Russinovich 站点中)。那将通过二进制文件进行 grep 确定。因此,您让这些“字符串”遍历整个源代码树,您将看到包含对错误清单(或其中包含错误版本的清单)的引用的二进制文件(dll 和静态库)。

于 2008-09-16T14:04:12.660 回答
4

另一个查看 exe 和 dll 清单的好工具是Manifest View,它不能在 XP 的全新安装上运行,因为依赖于 9.0.21022。

于 2009-10-14T17:17:14.450 回答
2

对于您的第三个选项,您可能可以在开发机器上的 C:\WINDOWS\WinSxS 目录中找到 9.0.21022 版本的 DLL 和清单。如果可以,那么您可以设置自己的 redist 目录并使用您的应用程序安装这些文件。

或者,您可以使用随 Visual Studio 提供的 9.0.30729.1 并伪造您随应用安装的清单,以报告它提供 9.0.21022 DLL,而不是 9.0.30729.1。运行时链接器似乎并不介意。有关更多信息,请参阅这个对解决这些问题非常有帮助的博客。

两种解决方法都解决了我在使用 VS2008 Express 将 DLL 部署为私有程序集时遇到的问题。

Roel 的答案是您的第一个选项(“正确修复”),但如果您依赖依赖于 9.0.21022 的库(因此您的清单列出了两个版本),那么第三个选项可能是唯一的如果您不想运行 vcredist_x86.exe,可以走的路。

于 2009-10-14T17:13:33.317 回答