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

断了今生、忘了曾经 提交于 2019-12-07 08:44:12

问题


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

I've tried putting this into 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:

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.

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.


回答1:


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

The trick is to remove from the application manifest the publicKey attribute on the assemblyIdentity so WinSxS is not used.

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

Then copy the necessary dlls:
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:

<?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.

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.

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

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="[^"]*"/$1 $2 version="9.0.30729.4148"/g;' extracted.manifest &&
  mt -nologo -manifest extracted.manifest -outputresource:"$res"
  regsvr32 /s "$file" || true
done



回答2:


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

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"

This is documented here:

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

Working 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.




回答3:


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...




回答4:


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

Navigate to 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.

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

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.

This will disable the newer runtime for the entire system.



来源:https://stackoverflow.com/questions/3097592/how-do-i-force-a-native-application-to-use-an-older-c-runtime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!