应用程序不与VS 2008 SP1 DLL一起运行,以前的版本与RTM版本一起使用

由于我们从Visual Studio 6切换到Visual Studio 2008,我们一直在使用MFC90.dll和msvc [pr] 90.dll以及清单文件在一个私人的并排configuration,以便不用担心版本或者将它们安装到系统中。

在SP1之前,这是工作正常(并仍然在我们的开发机器上正常工作)。 现在我们已经完成了SP1后的一些testing,自从昨天上午以来我一直在拉我的头发。

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

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

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

运行应用程序仍然得到以下错误:

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

我在谷歌或微软所做的search都没有提出任何与我的具体问题有关的事情(但是有这个错误消息的2005年的点击率)。

任何人有任何类似的问题与SP1?

选项:

  • find问题并解决问题,使其工作,因为它应该(首选)
  • 安装redist
  • 挖掘旧的RTM dll和清单文件,并删除#define使用当前的。 (我已经在早期的安装程序版本中获得了它们,因为微软将它们从您的redist文件夹中剔除)!

编辑:我已经尝试重新构buildclosures的定义(链接到RTM DLL),并且只要在文件夹中安装了RTM dll即可。 如果SP1 dll被放入,它会得到以下错误:

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

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

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

编辑:只是为了咧嘴笑,我下载并在我的testing机上运行VS2008SP1的vcredist_x86.exe。 工作。 使用SP1 DLL。 和我的RTM链接的应用程序。 但不是在SP1以前的私人并行分布。

我上个星期自己和这个问题作斗争,现在认为自己有点专家了)

我99%肯定,不是所有的dll和静态库都重新编译SP1版本。 你需要放

 #define _BIND_TO_CURRENT_MFC_VERSION 1 #define _BIND_TO_CURRENT_CRT_VERSION 1 

到你正在使用的每个项目。 对于真实世界大小的每一个项目,都很容易忘记一些没有重新编译的小型库。

有更多的标志定义要绑定的版本; 它logging在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)的最新版本。

然后,检查embedded式清单所说的内容。 下载XM资源编辑器: http : //www.wilsonc.demon.co.uk/d10resourceeditor.htm 。 打开每个DLL和EXE在你的解决scheme。 查看“XP主题清单”。 检查右侧的'版本'属性是'9.0.30729.1'。 如果是“9.0.21022”,则某个静态库正在拉取旧版本的清单。

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

debugging哪些库没有设置预处理器指令的好方法是:临时修改平台头,以便在试图embedded旧清单时停止编译。 打开C:\ Program Files \ Microsoft Visual Studio 9.0 \ VC \ crt \ include \ crtassem.h。 search“21022”string。 在那个定义中,把一些无效的东西(把'define'改成'blehbleh')。 这样,当你编译一个没有设置_BIND_TO_CURRENT_CRT_VERSION预处理器标志的项目时,你的编译将停止,你会知道你需要添加它们或者确保它被应用到任何地方。

另外,请确保使用Dependency Walker,以便知道正在将哪个dll插入。在虚拟机上安装最新的Windows XP副本(没有更新)(仅限SP2)是最简单的方法。 通过这种方式,您可以确定SxS文件夹中没有任何内容正在使用,而不是您提供的并行dll。

为了理解这个问题,我认为认识到有四个版本号是很重要的:

  • (A).exe编译的VC头文件的版本。
  • (B)embedded在该.exe的资源部分中的清单文件的版本。 默认情况下,这个清单文件是由Visual Studio自动生成的。
  • (C)与.exe相同的目录中复制的VC .DLLs(并行程序集的一部分)的版本。
  • (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:显示一个popup窗口,说:“程序入口点XYZXYZ不能位于dynamic链接库”。

  • 情况2:运行.exe时似乎没有任何事情发生,但Windows的“事件查看器/应用程序日志”中logging了以下事件:

    激活上下文生成失败的清单或策略文件“C:\ Path \ Microsoft.VC90.CRT.MANIFEST”在行4上的“C:\ Path \ file.exe”错误。在清单中find的组件标识与身份不匹配请求的组件。 参考是Microsoft.VC90.CRT,processorArchitecture =“x86”,publicKeyToken =“1fc8b3b9a1e18e3b”,types=“win32”,版本=“9.0.21022.8”。 定义是微软

  • 情况3:似乎一切正常。 这是remicles2的解决scheme 。

  • 情况4:这是应该如何做的 。 令人遗憾的是,正如Roel所说,实施起来可能相当困难。

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

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

更新 :最后我开始明白是怎么回事。 显然, Visual Studio在默认情况下为v2生成客户端代码(A) ,与我在一些微博上看到的相反。 _BIND_TO_CURRENT_VCLIBS_VERSION标志只select生成的清单文件(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 忽略此版本号默认情况下! 相反,除非使用“应用程序configuration文件” ,否则Windows将使用较新的版本(如果存在于系统中)。

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

总之

  • 对于专用程序集,请使用.exe项目中的_BIND_TO_CURRENT_VCLIBS_VERSION标志和所有相关的.lib项目。
  • 对于公共程序集,这不是必需的,因为Windows将自动从SxS目录中select正确版本的.DLL。

我只记得我用来找出哪个静态库行为不正常的另一个技巧:通过string“21022”的静态库“grep”。 不过,不要使用像wingrep这样的“正常”grep工具,因为它们不会显示这些string(他们认为这是一个二进制文件,并寻找原始的非Unicodestring)。 使用资源工具包中的“string”工具(现在在我认为的Russinovich网站中)。 那个会grep通过二进制文件。 所以你让这个“string”通过你的整个源代码树,你会看到二进制文件(dll和静态库),其中包含对错误清单(或错误版本的清单)的引用。

另一个用于查看exe和dll清单的好工具是Manifest View ,它足够合适,不会在XP的干净安装上运行,因为取决于9.0.21022。

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

或者,您可以使用随Visual Studio提供的9.0.30729.1版本,并伪装与您的应用程序一起安装的清单,以报告它提供了9.0.21022 DLL,而不是9.0.30729.1。 运行时链接程序似乎并不介意。 看到这个博客 ,这是非常有用的解决这些问题,获取更多信息。

这两个解决方法解决了我用VS2008 Express将DLL部署为私有程序集的问题。

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