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

时间:2008-09-12 17:59:54

标签: c++ visual-studio-2008 mfc

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

SP1之前,这工作正常(在我们的开发人员计算机上仍能正常工作)。现在我们已经在SP1之后做了一些测试,我从昨天早上开始就把头发拉了出来。

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

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

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

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

  
    

应用程序无法正确初始化(0xc0150002)。单击“确定”以终止该应用程序。

  

我在谷歌或微软上所做的任何搜索都没有提出任何与我的具体问题相关的信息(但是这些错误消息可以追溯到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链接应用程序。但 NOT 在SP1之前的私有并排发布中。

5 个答案:

答案 0 :(得分: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 Theme Manifest'。检查右侧的“版本”属性是否为“9.0.30729.1”。如果它是'9.0.21022',那么一些静态库正在拉入旧版本的清单。

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

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

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

答案 1 :(得分: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”的激活上下文生成失败。第4行的清单或策略文件“C:\ Path \ Microsoft.VC90.CRT.MANIFEST”中出现错误。清单中找到的组件标识不匹配所请求组件的标识。参考是Microsoft.VC90.CRT,processorArchitecture =“x86”,publicKeyToken =“1fc8b3b9a1e18e3b”,type =“win32”,version =“9.0.21022.8”。定义是Microsoft

  • 情况3:一切似乎都运转正常。这是remicles2's solution

  • 情况4:这是how it should be done。遗憾的是,正如罗尔所说,实施起来可能相当困难。

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

注意这整个解释仍然在private assemblies的背景下。

更新:最后我开始了解发生了什么。显然,Visual Studio generates client code (A) for v2 by default,与我在一些微软博客上看到的相反。 _BIND_TO_CURRENT_VCLIBS_VERSION标志仅选择生成的清单文件(B)中的版本,但在运行应用程序时将忽略此版本。

结论

默认情况下,由Visual Studio 2008编译的.exe链接到最新版本的VC90 DLL。您可以use the _BIND_TO_CURRENT_VCLIBS_VERSION flag控制将在清单文件中生成哪个版本的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将使用较新的版本(如果系统中存在),但使用when an "application configuration file"除外。

我是唯一一个认为这令人困惑的人吗?

总结

  • 对于私有程序集,请在.exe的项目中使用_BIND_TO_CURRENT_VCLIBS_VERSION标志,并使用所有依赖的.lib项目。
  • 对于公共程序集,这不是必需的,因为Windows将自动从SxS目录中选择正确版本的.DLL。

答案 2 :(得分:4)

我只记得另一个技巧,我曾经发现哪些静态库不正常:'grep'通过静态库找到字符串'21022'。但是,不要使用像wingrep这样的'普通'grep工具,因为他们不会向你展示这些字符串(他们认为这是一个二进制文件,并寻找原始的非unicode字符串)。使用资源工具包中的'strings'实用程序(我认为现在在Russinovich网站上)。那个人会通过二进制文件grep。所以你让这个'字符串'遍历你的整个源代码树,你会看到包含错误清单引用的二进制文件(dll和静态库)(或者包含错误版本的清单)。

答案 3 :(得分:4)

查看exe和dll清单的另一个不错的工具是Manifest View,这非常适合在干净安装的XP上运行,因为 it 取决于9.0.21022。

答案 4 :(得分:2)

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

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

这两个变通方法修复了我将DLL作为私有程序集部署VS2008 Express所遇到的问题。

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