博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
VC分发包版本问题
阅读量:5213 次
发布时间:2019-06-14

本文共 16804 字,大约阅读时间需要 56 分钟。

来源:

 

之前曾经写过一篇个人经历,是关于VC2005分发包版本不一致而引起应用程序无法正常启动的()。这篇文章里只是介绍了个人在开发过程中遇到的一个非常极品的问题,但是没有给出更多详细的信息和解决方法。今日偶然看到一篇牛人写的文章,顺手翻译下来,总算了了长久以来的心愿。

原文地址:

 

/// 原文

VC redistributable security update -KB971090 mitigation problem

Problem

After installing KB971090 for Visual C++ 2005 SP1, the version of ATL/MFC/CRT referenced in the generated manifests is changed from 8.0.50727.762 to 8.0.50727.4053

The above change forces the application developer to rebuild all components to reference the 4053 version of the versions of ATL/MFC/CRT in the manifest, as well as making it necessary to ship a new vcredist_x86.exe and/or MSM files containing the new 4053 versions of ATL/MFC/CRT.

Solution

Instead of uninstalling the KB971090 update, we can force the build to use the 8.0.50727.762 version instead of the default which is 8.0.50727.4053. Microsoft provides a mechanism to specify the assembly version number to use in the manifests.

Steps to take to allow your applications to reference 8.0.50727.762 instead of 8.0.50727.4053

1) Create a file named targetsxs.h with the following content and put it in a common location

#ifndef __midl

#define _SXS_ASSEMBLY_VERSION "8.0.50727.762"
#define _CRT_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION
#define _MFC_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION
#define _ATL_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION

#ifdef __cplusplus

extern "C" {
#endif
__declspec(selectany) int _forceCRTManifest;
__declspec(selectany) int _forceMFCManifest;
__declspec(selectany) int _forceAtlDllManifest;
__declspec(selectany) int _forceCRTManifestRTM;
__declspec(selectany) int _forceMFCManifestRTM;
__declspec(selectany) int _forceAtlDllManifestRTM;
#ifdef __cplusplus
}
#endif
#endif

2) The above file needs to be included in every project you wish to build.

Accomplish this in one of two ways. The first method involves the changing of source code. The second involves changing of project settings.

choose A or B which ever one is more appropriate for your situation:

A) #include "targetsxs.h" near the top of every one of your stdafx.h files

(using the path you saved the targetsxs.h)

B) Use the force include (/FI) compile option to make sure that the above file is included in every file built. To accomplish that, add the following command line to your compiler options

/FIc:\path\targetsxs.h

(where c:\path is the location of the targetsxs.h you created in step 1)

There are two methods to accomplish that: either directly in your project or through a compiler environment variable:

Method i)

Add the above to the command line section of the C/C++ project properties.

Method ii)

Create an environment variable named CL with the above-mentioned /FI statement

Method (ii) is more convenient to use when you have dozens of projects that you do not wish to make changes to, but may conflict with other work you do on your machine.

3) For every MFC DLL project in your solution add the following line to the bottom of the stdafx.cpp file

#include "..\src\mfc\dllmodul.cpp"

Step three is only necessary if you have any MFC DLL projects (this step is necessary due to a bug in the handling of the assembly versions in MFC DLLs – the bug is that a reference to the latest version of the DLLs will always be included regardless of what is set in step 1)

4) Do a rebuild all of all the projects in your solution

5) Inspect manifest files (by doing a find in files for *.intermediate.manifest) to ensure that 4053 no longer appears in any of the manifests.

6) Run your app on a machine that has no 4053 components installed to WinSxS to make sure runs properly.

IMPORTANT NOTE: if you have ATL controls that are affected by this security problem please ensure you have followed the directions to modify your controls to take advantage of the security updates. A simple recompile may not be enough. For more info please see the video at:

http://channel9.msdn.com/posts/Charles/Out-of-Band-Inside-the-ATL-Security-Update/

Q&A

Does referencing 762 instead of 4053 make your application less secure?

No. Microsoft provides WinSxS policy redirection, so any application referencing 762 will end up loading the 4053 versions (if they’re installed). The ATL security update redistributable has been released as an update on Windows Update, so the 4053 version of ATL will be in place, and will be used even though your app still references the 762 version of ATL.

*Important note: you should still ship the new version of the redistributable if at all possible, as users may have not updated using Windows Update.

What are the benefits to referencing 762 instead of 4053 in your SP1 applications?

1) If you have existing applications shipped and you need to rebuild any components shipped, then new MSM or vcredist_x86.exe containing 4053 versions do not need to be shipped. You can continue to ship existing components with 762 versions.

2) If you have existing third party static libraries that reference 762, then you need not rebuild them to reference 4053.

Does VC2008 SP1 security update have a similar issue?
Yes, it does, if you use _BIND_TO_CURRENT_VCLIBS_VERSION in your project. It will bind to the security update version instead of the SP1 version. You can use a similar technique as described above (step 3 is not required) to get around this problem.

For VC2008 SP1 the values for the current versions of the CRT/MFC/ATL have changed slightly, instead of _forceCRTManifest, you should use _forceCRTManifestCUR.  The same thing applies for MFC/ATL (add the CUR). And of course, the version numbers you’re dealing with are different: SP1 9.0.30729.1 vs the new SP1+security update which is 9.0.30729.4148

 

/ 译文 /

VC分发包安全更新--KB971090的修正之道

 

[注]

KB971090的描述:

KB971090的下载地址:

 

[问题描述]

在安装了Visual C++ 2005 SP1的KB971090安全更新后,VC生成的manifest中引用的ATL/MFC/CRT库的版本从8.0.50727.762变成了8.0.50727.4053。

正因为上面的变动,导致了应用程序开发者必须重新编译所有的组件使它们在manifest中指向4053版本的ATL/MFC/CRT库,同时在发布应用程序的时候还必须部署一个新的vcredist_x86.exe(对应8.0.50727.4053版本)或者在安装文件中内嵌包含了最新4053版本的ATL/MFC/CRG库的MSM文件。

 

[解决之道]

除了卸载KB971090更新之外,我们还可以强制使用8.0.50727.762版本的库来替换此时默认8.0.50727.4053的库。Microsoft提供了一种在manifest文件中指定使用哪种版本编译库的机制。

使得你的应用程序从指向8.0.50727.4053变为指向8.0.50727.762的步骤如下:

1) 创建一个名为targetsxs.h的头文件,填入下面的内容,保存在某个固定目录下。

#ifndef __midl

#define _SXS_ASSEMBLY_VERSION "8.0.50727.762"
#define _CRT_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION //覆盖掉Microsoft Visual Studio 8\VC\include\crtassem.h中的同名宏
#define _MFC_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION //覆盖掉Microsoft Visual Studio 8\VC\atlmfc\include\atlassem.h中的同名宏
#define _ATL_ASSEMBLY_VERSION _SXS_ASSEMBLY_VERSION //覆盖掉Microsoft Visual Studio 8\VC\atlmfc\include\MFCassem.h中的同名宏

#ifdef __cplusplus

extern "C" {
#endif
    __declspec(selectany) int _forceCRTManifest;
    __declspec(selectany) int _forceMFCManifest;
    __declspec(selectany) int _forceAtlDllManifest;
    __declspec(selectany) int _forceCRTManifestRTM;
    __declspec(selectany) int _forceMFCManifestRTM;
    __declspec(selectany) int _forceAtlDllManifestRTM;
#ifdef __cplusplus
}
#endif
#endif

 

2) 你需要在每个你希望编译的项目中包含上面的头文件。

可以通过两种方法来达成这个目的。第一个方法是涉及到修改源代码。第二个方法涉及到修改项目设置。到底选择方法A好还是方法B好?这适合取决于你当前的应用环境:

A) 在你的每一个stdafx.h头文件的头部包含"targetsxs.h"头文件

(使用你保存targetsxs.h的路径)

B) 强制使用(/FI)编译选项来保证每个文件编译时都包含上面的头文件(targetsxs.h)。为了达到这个目的,你可以在你的编译器选项中添加如下的命令行

/FIc:\path\targetsxs.h

(/FI:预处理指定的头文件,与源文件中的#include有相同效果(强制包含头文件)。c:\path是你在第一步中创建的targetsxs.h的保存位置)

可以使用两个方法在编译器选项中到达这个目的:在你的工程中直接设置或者通过编译器环境变量来设置:

方法1:

在工程属性c/c++ => 高级 => 强制包含 里加上c:\path\targetsxs.h

将上面的命令添加到C/C++工程属性的命令行中

(在工程属性的c/c++ => command line里加上 /FI c:\path\targetsxs.h 。就能指定使用哪个库了)

 

方法2:

用上面提到的/FI语法创建一个名为CL的环境变量

当你有很多工程的时候,你肯定不希望一个一个地去修改它们的工程属性,这个时候方法2就方便很多,但同时这个环境变量也可能会影响到你机器上的其他工程。

 

3) 对于你项目清单中的每个MFC DLL工程,你需要在stdafx.cpp文件的底部添加下面一行代码

#include "..\src\mfc\dllmodul.cpp"

只有当你使用了MFC DLL工程的时候,这一步才是必需的(之所以是必需的是因为在MFC DLL中处理汇编代码(assembly versions)时的一个Bug - 如果没有包含dllmodul.cpp的话,步骤一设置的东西就不会被包含而编译器会始终引用最新版本的DLL)。

 

4) 编译你的项目清单中的所有工程。

 

5) 检查manifeset文件(就是编译器生成的那些*.intermediate.manifest文件)以确保4053不会出现在任何manifest文件中。

 

6) 在一台没有安装4053版本WinSxS组件机器上运行你的应用程序来验证它可以正常运行。

 

重要提示:如果你被ATL控件的安全性问题所影响(而必须要安装这个更新)的话,还是请你安装此更新以便使用更加安全的ATL控件。此时,简单的重编译可能并不足够,比需要从下面的视频中得到更多的信息:

 

 

 

Q&A

 

1.使用762版本的组件来代替4053是否会使得你的应用程序安全性降低?

不会。微软提供了一种WinSxS重定位策略,所以任何引用到762版本ATL的应用程序都最终会应用到4053版本(如果你安装了它们的话)。这个ATL安全更新已经作为Window Update的更新发布了,所以一旦你保持了与Window Update同步的更新,那么你就已经准备好使用4053版本的ATL了,即使你的应用程序仍然引用了762版本的ATL,你最终还是会使用4053版本的ATL。

*重要提示:如果可能的话,你最好还是把最新版本的分发包随你的应用程序一起发布,因为用户有可能并不会使用Window Update来更新最新的组件。

 

2.在你的SP1应用程序中引用762版本来代替4053有什么好处么?

1) 如果你有一些应用程序已经发布了但是必须重新编译某些已经发布出去的组件,那么你就不用再发布新的MSM或者包含4053版本的vcrdist_x86.exe了。你可以继续使用762版本来发布现有的组件。

2) 如果你有使用引用到762版本的第三方静态库的话,你也不需要将它们重新编译到4053版本。

 

3.VC2008 SP1安全更新是否有同样的问题呢?

是的,如果你在你的工程中使用了_BING_TO_CURRENT_VCLIBS_VERSION,那么就会有同样的问题。它将会绑定到最新版本的安全更新来代替原来的SP1版本。你同样可以使用上面描述的方法(步骤3不需要)来解决这个问题。

对于VC2008 SP1,CRT/MFC/ATL的当前版本号有些许变化,你应该使用_forceCRTManifestCUR来代替_forceCRTManifest。对于MFC/ATL也必须使用同样的设置(添加CUR)。当然,此时你所面对的版本号也是不同的:SP1是9.0.30729.1,而最新的SP1+安全更新则是9.0.30729.4148。

 

 

 

PS:由于个人实在无法忍受,每次编译出来的DLL都要手动去修改其资源文件中的Manifest(使用ResHacker删除掉有关4053版本的Manifest节点),所以今天一狠心,直接将工作机上所有关于VC2005的东东全部干掉,再重新安装一次,虽然浪费了很多时间,但是还是这种釜底抽薪的方法最有效。 

 

============

WDF debug版本的.manifest文件(WDF.dll.intermediate.manifest)

 publicKeyToken属性告诉加载器在Windows XP/2003/Vista系统研究的SxS存储所需的DLL

 

清单

对于指定使用C:\ WINDOWS \ WinSxS文件夹下的不同版本的.dll有用的

 

清单可以不生成,在连接器-清单文件-生成清单,改为否(默认为是)。

也可以指定清单生成的地方(在清单工具-输入和输出-嵌入清单 进行设置),共有两个地方:程序集中,独立文件。
这个功能VC很早就有了

1.清单在exe和dll等中,默认方式。(指明了这次编译出来的东西,需要用到的清单)。

2.清单是做为一个独立的文件存在(*.manifest)  (在xp以上系统上跑程序,才支持)

 

 

 在程序中指定使用某个模块的清单??

#ifdef _DEBUG

#define __LIBRARIES_SUB_VERSION    "Debug"
#else
#define __LIBRARIES_SUB_VERSION    ""
#endif
 
// Manifest for the CRT
#pragma comment(linker,"/manifestdependency:\"type='win32' " \
    "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".
    " __LIBRARIES_SUB_VERSION "CRT' " \
    "version='" _CRT_ASSEMBLY_VERSION "' " \
    "processorArchitecture='x86' \"")

// Manifest for the MFC

#pragma comment(linker,"/manifestdependency:\"type='win32' " \
    "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".
    " __LIBRARIES_SUB_VERSION "MFC' " \
    "version='" _CRT_ASSEMBLY_VERSION "' " \
    "processorArchitecture='x86'\"")

#pragma comment(linker,"/manifestdependency:\"type='win32' " \

    "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFCLOC' " \
    "version='" _CRT_ASSEMBLY_VERSION "' " \
    "processorArchitecture='x86'\"")

  

<?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='requireAdministrator' 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>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC90.DebugMFC' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*' />
    </dependentAssembly>
  </dependency>
</assembly>

 

WDF release版本的.manifest文件(WDF.dll.intermediate.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.CRT' version='9.0.30729.9463' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC90.MFC' version='9.0.30729.9463' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*' />
    </dependentAssembly>
  </dependency>
</assembly>

============

部署VC2008应用程序

来源:

 

 

 

如果你编译了一个VC2008的默认的CRT/MFC的应用程序,如果目标部署电脑上没有安装相应的VC2008的动态库,当运行你的程序的时个,会出现如下错误信息.

-------

由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题。
---------

 

如果是一个dll,则有可能出现

-------

应用程序非法关闭!为您带来的不便,我们十分抱歉!

---------

这是因为程序使用了基于VC2008的CRT/MFC的动态库版本.

解决这个问题,有三种方法:

1.使用静态链接库编译(缺点,生成的exe的程序过于庞大)

2.使用 / 将VC2008的发行版的DLL安装在你的系统上.(缺点,只能支持发行版,调试版程序不能支持)

3.将你的程序依赖的CRT/MFC的动态库与你的程序一起发布(放在与你的发布程序同一目录中)

 

第一种和第二种就不详细讲如何实现了,只要讲第三种方法如何实现.优其是程序的开发是使用了VC2008 SP1的版本开发的程序.

 

在你的VC2008的安装目录下有两个目录(这个是release版本的),

  • C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/redist/x86/Microsoft.VC90.CRT
  • C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/redist/x86/Microsoft.VC90.MFC

debug版本是在

  • C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/redist/Debug_NonRedist/x86/Microsoft.VC90.DebugCRT
  • C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/redist/Debug_NonRedist/x86/Microsoft.VC90.DebugMFC

 

只要将这两个目录下的文件一同拷贝到发布程序的同一目录下

  • Microsoft.VC90.CRT.manifest
  • msvcr90.dll
  • msvcp90.dll
  • msvcm90.dll
  • Microsoft.VC90.MFC.manifest
  • mfc90.dll
  • mfc90u.dll
  • mfcm90.dll
  • mfcm90u.dll

这些是这个程序依赖的发行版动态库,同理,如果是调试版的发布程序,也一样把相应的调试动态库拷贝到相应目录.

程序如你意运行起来了!

  注意:Microsoft.VC90.MFCLOC 是MFC的本地版本

 C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/redist/Debug_NonRedist

 

但是,如果你安装的是VC2008 SP1的版本的时候,问题就来了,你的程序也一样运行不起来了!

原因就是安装了VC2008 SP1的时候,它把"VC/redist"用新的版本文件代替了,问题不大,但是,这个程序的版本是依赖于新的manifest的文件的,当你编译VC2008-SP1的程序的时候,它同时把RTM-version写入程序的manifest文件中,这个是旧的RTM-version,不与新版本的VC2008-SP1的"CRT/MFC"manifest版本一致,因此程序运行的时候是拒绝导入这些新的VC2008-SP1的CRT/MFC的运态库!

 

解决方法有两种.

 

方法一:

最简单的,修改Microsoft.VC90.CRT.manifest和Microsoft.VC90.MFC.manifest文件,将新的版本号改为旧的版本号,如果是依赖其它的Microsoft.VC90.*.manifest的文件,也同样是如此修改!

如果是装了VC2008-SP1后,它的版本号是“9.0.30729.8″

未装VC2008-SP1前的版本号为"9.0.21022.8"

过程如下:

将所依的动态库的及它们的 manifest 文件拷贝到发布应用程序的同一目录下,并修改Microsoft.VC90.*.manifest文件,将

version="9.0.30729.1"

修改为

version="9.0.21022.8"
恭喜你,你的程序运行起来了!
方法二
修改你的程序的所依赖的manifest,这样程序会依整于新的manifest.
过程如下:

stdafx.h 这个文件中,增加如下宏定义:
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1
程序编译后就会依赖于新的manifest,版本号为 "9.0.30729.1"
无须再修改manifest文件中的version版本号了.
将所依的动态库的及它们的 manifest 文件拷贝到发布应用程序的同一目录下
恭喜你,程序又运行起来了!
注意:如果你是想要新的MFC-feature-pack的功能,用这种方法是最好的.
注意一点,非常重要,如果已经安装了vcredist_*.exe程序包,注意的是Dll会自动把引用调到系统目录下的WinSxS目录下的,即不再引用同一目录下的动态库!
如果是编译时使用了(/clr)这个编译选项去支持.net开发,你必须要安装.net framework redistributable包!
不过,在2010,编译的程序会不再需要manifest文件!

 

方法三:

找windows/winsxs/目录下对应版本的文件以及 .manifest 文件拷过去试试

方法四:

使用资源修改工具,例如ResHacker来将编译出来的DLL中的Manifest信息进行修改,改成合适的版本,使得这个版本号与发布产品时使用的VC2005的版本一致。

 这个办法是肯定可行的,但是每次递交的时候,都要去修改,那岂不是很麻烦

方法五:

来源:

在这个男人的VC2005中搜索8.0.50727.4053的字符串,会发现在以下三个文件有这个字符串:

Find all "8.0.50727.4053", Match case, Subfolders, Find Results 2, "Visual C++ Include Directories"
Cannot access E:\Tools\Microsoft Visual Studio 8\VC\PlatformSDK\common\include
  E:\Tools\Microsoft Visual Studio 8\VC\include\crtassem.h(23):#define _CRT_ASSEMBLY_VERSION "8.0.50727.4053"
  E:\Tools\Microsoft Visual Studio 8\VC\atlmfc\include\atlassem.h(22):#define _ATL_ASSEMBLY_VERSION "8.0.50727.4053"
  E:\Tools\Microsoft Visual Studio 8\VC\atlmfc\include\MFCassem.h(22):#define _MFC_ASSEMBLY_VERSION "8.0.50727.4053"
Matching lines: 3    Matching files: 3    Total files searched: 3423
  可以看到这三个文件分别对应了微软的CRT库/ATL库/MFC库。
  打开其中一个文件E:\Tools\Microsoft Visual Studio 8\VC\include\crtassem.h
#pragma once
#ifndef _VC_ASSEMBLY_PUBLICKEYTOKEN
#define _VC_ASSEMBLY_PUBLICKEYTOKEN "1fc8b3b9a1e18e3b"
#endif
#ifndef _CRT_ASSEMBLY_VERSION
#if defined _USE_RTM_VERSION
#define _CRT_ASSEMBLY_VERSION "8.0.50608.0"
#else
#define _CRT_ASSEMBLY_VERSION "8.0.50727.4053"
#endif
#endif
#ifndef __LIBRARIES_ASSEMBLY_NAME_PREFIX
#define __LIBRARIES_ASSEMBLY_NAME_PREFIX "Microsoft.VC80"
#endif
/
尝试一下将#define _CRT_ASSEMBLY_VERSION "8.0.50727.4053"改为#define _CRT_ASSEMBLY_VERSION "8.0.50727.762",是不是就可以了呢?但是事实却无情地摧毁了这个男人的信心。因为实际编译出来的DLL中除了8.0.50727.4053这个Manifest信息之外,又多了一个新8.0.5.727.762的节点,但是似乎这样并不能让Windows去按照Manifest策略加载DLL(不是按照“或”的逻辑加载,而是按照“与”的逻辑),只能将4053这个节点删除,只保留762这个节点,才能正确加载DLL。
  后来再狗狗的时候,发现了国外的一篇讨论帖,貌似对这个问题有很好的解释(http://www.dotnetmonster.com/Uwe/Forum.aspx/dotnet-vc/11078/),其中有一个回复:
the problem was the latest security update for Visual C++ 2005 SP1.
It forces your app to use a newer version of CRT and MFC (8.0.50727.4053
instead of 8.0.50727.762)
To fix this, (my recommended approach) go to add/remove programs (with show
updates checked) and uninstalll KB971090, or (will work, but is a pain) send
them the newest vcredist_x86.exe from the bootstrapper folder on your hard
drive.
基本也说明了本篇文章的目的。但是在这个男人的系统上,并没有这个补丁啊?只有一个KB973923,不知道会不会是因为这个原因:

转载于:https://www.cnblogs.com/spriteflk/p/4018461.html

你可能感兴趣的文章
BS调用本地应用程序的步骤
查看>>
常用到的多种锁(随时可能修改)
查看>>
用UL标签+CSS实现的柱状图
查看>>
mfc Edit控件属性
查看>>
Linq使用Join/在Razor中两次反射取属性值
查看>>
[Linux]PHP-FPM与NGINX的两种通讯方式
查看>>
Java实现二分查找
查看>>
优秀员工一定要升职吗
查看>>
[LintCode] 462 Total Occurrence of Target
查看>>
springboot---redis缓存的使用
查看>>
架构图-模型
查看>>
sql常见面试题
查看>>
jQuery总结第一天
查看>>
Java -- Swing 组件使用
查看>>
Software--Architecture--DesignPattern IoC, Factory Method, Source Locator
查看>>
poj1936---subsequence(判断子串)
查看>>
黑马程序员_Java基础枚举类型
查看>>
【redis4 】
查看>>
[ python ] 练习作业 - 2
查看>>
一位90后程序员的自述:如何从年薪3w到30w!
查看>>