windows 如何强制本机应用程序使用较旧的 C 运行时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3097592/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 14:42:18  来源:igfitidea点击:

How do I force a native application to use an older C runtime

windowsvisual-c++manifestconfigwinsxs

提问by Kevin Smyth

Visual Studio 2010 installs version ...4974 of the VC9 runtime whose .pdbs are unavailable. How can I force my GME.exeto use an older VC9 runtime?

Visual Studio 2010 安装了 VC9 运行时的 ...4974 版本,其.pdbs 不可用。如何强制我GME.exe使用较旧的 VC9 运行时?

I've tried putting this into GME.exe.config:

我试过把它放进去GME.exe.config

<?xml version="1.0"?>
<configuration>
  <windows>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <assemblyIdentity type="win32" name="GME" processorArchitecture="x86" version="1.0.0.1"/>
      <dependentAssembly>
        <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" publicKeyToken="1fc8b3b9a1e18e3b" processorArchitecture="x86" />
        <bindingRedirect oldVersion="9.0.21022.8-9.0.21022.4974" newVersion="9.0.30729.4148" />
        <bindingRedirect oldVersion="9.0.30729.0-9.0.30729.4974" newVersion="9.0.30729.4148" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity type="win32" name="Microsoft.VC90.MFC" publicKeyToken="1fc8b3b9a1e18e3b" processorArchitecture="x86" />
        <bindingRedirect oldVersion="9.0.21022.8-9.0.21022.4974" newVersion="9.0.30729.4148" />
        <bindingRedirect oldVersion="9.0.30729.0-9.0.30729.4974" newVersion="9.0.30729.4148" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity type="win32" name="Microsoft.VC90.ATL" publicKeyToken="1fc8b3b9a1e18e3b" processorArchitecture="x86" />
        <bindingRedirect oldVersion="9.0.21022.8-9.0.21022.4974" newVersion="9.0.30729.4148" />
        <bindingRedirect oldVersion="9.0.30729.0-9.0.30729.4974" newVersion="9.0.30729.4148" />
      </dependentAssembly>
    </assemblyBinding>
  </windows>
</configuration>

However, sxstrace reports:

但是,sxstrace 报告:

INFO: Resolving reference Microsoft.VC90.CRT,processorArchitecture="x86",publicKeyToken="1fc8b3b9a1e18e3b",type="win32",version="9.0.21022.8"
....
INFO: Publisher Policy redirected assembly version.

Adding <publisherPolicy apply="no"/>under <dependentAssembly>results in ERROR: Activation Context generation failed.with no other helpful information on Windows 7.

在 Windows 7 上没有其他有用信息的情况<publisherPolicy apply="no"/>下添加下<dependentAssembly>结果ERROR: Activation Context generation failed.

Note this is only for debugging my local copy, not redistribution, so I'm not worried about security updates or other benefits of the publisher policy.

请注意,这仅用于调试我的本地副本,而不是重新分发,因此我不担心安全更新或发布者策略的其他好处。

采纳答案by Kevin Smyth

Here's the trick to get the Application Config to work with Win2003 and later:

这是使应用程序配置与 Win2003 及更高版本一起使用的技巧:

http://www.tech-archive.net/Archive/VC/microsoft.public.vc.ide_general/2008-01/msg00033.html

http://www.tech-archive.net/Archive/VC/microsoft.public.vc.ide_general/2008-01/msg00033.html

Essentially, one needs to add the app to the compatibility database with "EnableAppConfig"

本质上,需要使用“EnableAppConfig”将应用程序添加到兼容性数据库中

This is documented here:

这是记录在这里:

http://msdn.microsoft.com/en-us/library/ee710783%28VS.85%29.aspx

http://msdn.microsoft.com/en-us/library/ee710783%28VS.85%29.aspx

Working GME.exe.Config:

工作GME.exe.Config

<?xml version="1.0"?>
<configuration>
  <windows>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
        <publisherPolicy apply="no"/>
        <bindingRedirect oldVersion="9.0.21022.0-9.0.21022.4974" newVersion="9.0.30729.1" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity type="win32" name="Microsoft.VC90.MFC" publicKeyToken="1fc8b3b9a1e18e3b" processorArchitecture="x86"/>
        <publisherPolicy apply="no"/>
        <bindingRedirect oldVersion="9.0.21022.0-9.0.21022.4974" newVersion="9.0.30729.1" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity type="win32" name="Microsoft.VC90.ATL" publicKeyToken="1fc8b3b9a1e18e3b" processorArchitecture="x86"/>
        <publisherPolicy apply="no"/>
        <bindingRedirect oldVersion="9.0.21022.0-9.0.21022.4974" newVersion="9.0.30729.1" />
      </dependentAssembly>

    </assemblyBinding>
  </windows>
</configuration>

It seems one needs to do this for loaded .dlls too.

似乎也需要为加载的 .dll 执行此操作。

回答by Kevin Smyth

The answer comes from http://blog.kalmbachnet.de/?postid=80

答案来自http://blog.kalmbachnet.de/?postid=80

The trick is to remove from the application manifest the publicKeyattribute on the assemblyIdentityso WinSxS is not used.

诀窍是从应用程序清单中删除该publicKey属性,assemblyIdentity以便不使用 WinSxS。

GME.exe.manifest:

GME.exe.manifest

<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"></requestedExecutionLevel>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.30729.4148" processorArchitecture="x86">
      </assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC90.MFC" version="9.0.30729.4148" processorArchitecture="x86">
      </assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC90.ATL" version="9.0.30729.4148" processorArchitecture="x86">
      </assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*">
      </assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>

Embed the manifest into GME.exe(substitute 1 for 2 for modifying dlls):
mt -manifest GME.exe.manifest -outputresource:GME.exe;1

将清单嵌入GME.exe(用 1 代替 2 以修改 dll):
mt -manifest GME.exe.manifest -outputresource:GME.exe;1

Then copy the necessary dlls:
cp -a windows/winsxs/x86_microsoft.vc90.{atl,crt,mfc}*30729.4148*/*dll path-to-app/

然后复制必要的dll:
cp -a windows/winsxs/x86_microsoft.vc90.{atl,crt,mfc}*30729.4148*/*dll path-to-app/

Then create manifests for each assembly that SxS isn't being used for and place them next to the application. The manifests are based on e.g. C:\Windows\WinSxS\Manifests\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_5090ab56bcba71c2.manifest:
Microsoft.VC90.CRT.Manifest:

然后为每个未使用 SxS 的程序集创建清单,并将它们放在应用程序旁边。该清单是基于如C:\Windows\WinSxS\Manifests\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_5090ab56bcba71c2.manifest
Microsoft.VC90.CRT.Manifest

<?xml version="1.0"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.30729.4148" processorArchitecture="x86"></assemblyIdentity>
    <file name="msvcr90.dll"></file>
    <file name="msvcp90.dll"></file>
    <file name="msvcm90.dll"></file>
</assembly>

It is not possible to remove the assembly references from the application manifest, as the CRT complains that it is not being loaded via SxS.

无法从应用程序清单中删除程序集引用,因为 CRT 抱怨它不是通过 SxS 加载的。

Unfortunately it seems one must modify the manifest for every dependent dll in the application, including the dlls copied from WinSxS, or multiple versions may be loaded.

不幸的是,似乎必须修改应用程序中每个依赖 dll 的清单,包括从 WinSxS 复制的 dll,否则可能会加载多个版本。

Here's a bash script that worked for me, where ~/Documents/sxs-hack/ contains the CRT dlls and modified manifests:

这是一个对我有用的 bash 脚本,其中 ~/Documents/sxs-hack/ 包含 CRT dll 和修改后的清单:

rm -rf bin
mkdir bin
cp -a ~/Documents/sxs-hack/* bin/
find -iname \*.dll -or -iname \*.ocx -or -iname \*.exe | while read -r file; do
  cp -a "$file" bin/"$(basename $file)"
  export file=bin/"$(basename $file)"
  export res=$file\;2
  if [ ${file:${#file}-3} = "exe" ]; then export res=$file\;1; fi
  echo $file
  mt.exe -nologo -inputresource:"$res" -out:extracted.manifest &&
  perl -pli -e 's/(Microsoft.VC90.[^>]*)version="[^"]*"([^>]*)publicKeyToken="[^"]*"/  version="9.0.30729.4148"/g;' extracted.manifest &&
  mt -nologo -manifest extracted.manifest -outputresource:"$res"
  regsvr32 /s "$file" || true
done

回答by Shea

If you've got the source you could always statically link the c-runtime library that you want to use... Not always the greatest idea but if you've inherited a monster library that will only run in debug mode and can't redistribute the debug CRT it'll do the trick...

如果你有源代码,你总是可以静态链接你想要使用的 c-runtime 库......这并不总是最好的主意,但如果你继承了一个只能在调试模式下运行并且不能运行的怪物库重新分发调试 CRT 就可以了...

回答by Kevin Smyth

Here's how to disable the publisher policy on Vista or 7:

以下是在 Vista 或 7 上禁用发布者策略的方法:

Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Winners\x86_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_none_02d0010672fd8219\9.0

导航到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Winners\x86_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_none_02d0010672fd8219\9.0

Set the Default key to the version you want, e.g. 9.0.30729.4148. Set the version you don't want to 0, e.g. "9.0.30729.4974"=00.

将默认密钥设置为您想要的版本,例如 9.0.30729.4148。将您不想要的版本设置为 0,例如“9.0.30729.4974”=00。

You must do this for crt, atl, mfc, etc.

您必须为 crt、atl、mfc 等执行此操作。

WinSxS seems to cache the policy. This worked for me: touch(1) the application, then set HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\PublisherPolicyChangeTime to something low, e.g. 10.

WinSxS 似乎缓存了策略。这对我有用:触摸(1)应用程序,然后将 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\PublisherPolicyChangeTime 设置为较低的值,例如 10。

This will disable the newer runtime for the entire system.

这将为整个系统禁用较新的运行时。