1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
< assembly xmlns = "urn:schemas-microsoft-com:asm.v1" manifestVersion = "1.0" > < dependency > < dependentAssembly > < assemblyIdentity type = "win32" name = "Microsoft.VC80.DebugCRT" version = "8.0.50608.0" processorArchitecture = "x86" publicKeyToken = "1fc8b3b9a1e18e3b" ></ assemblyIdentity > </ dependentAssembly > </ dependency > < dependency > < dependentAssembly > < assemblyIdentity type = "win32" name = "Microsoft.VC80.DebugMFC" version = "8.0.50608.0" processorArchitecture = "x86" publicKeyToken = "1fc8b3b9a1e18e3b" ></ 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 > |
In addition to the DLLs, the relevant files and directories from the 'Manifests' and 'Policies' directories must also be copied to the computer requiring the runtime. The directory structure must be maintained! The operative strings are:
- x86_Microsoft.VC80.DebugCRT_1fc8b3b9a1e18e3b_8.0.50727.42_x-ww_f75eb16c
- x86_Microsoft.VC80.DebugMFC_1fc8b3b9a1e18e3b_8.0.50727.42_x-ww_c8452471
Once all the files have been copied, all MFC 8 applications will be loaded! (Whether the applications run perfectly depends on their own code…)
For an example of the directories and files that need to be copied, see this. It could be inflated upon the Windows directory while maintaining its structure.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?> < assembly xmlns = "urn:schemas-microsoft-com:asm.v1" manifestVersion = "1.0" > < noInheritable /> < assemblyIdentity type = "win32" name = "Microsoft.VC80.CRT" version = "8.0.50727.1833" processorArchitecture = "x86" publicKeyToken = "1fc8b3b9a1e18e3b" /> < file name = "msvcr80.dll" /> < file name = "msvcp80.dll" /> < file name = "msvcm80.dll" /> </ assembly > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#ifndef _VC_ASSEMBLY_PUBLICKEYTOKEN #define _VC_ASSEMBLY_PUBLICKEYTOKEN "1fc8b3b9a1e18e3b" #endif #if !defined(_BIND_TO_CURRENT_VCLIBS_VERSION) #define _BIND_TO_CURRENT_VCLIBS_VERSION 0 #endif #if !defined(_BIND_TO_CURRENT_CRT_VERSION) #if _BIND_TO_CURRENT_VCLIBS_VERSION #define _BIND_TO_CURRENT_CRT_VERSION 1 #else #define _BIND_TO_CURRENT_CRT_VERSION 0 #endif #endif #ifndef _CRT_ASSEMBLY_VERSION #if _BIND_TO_CURRENT_CRT_VERSION #define _CRT_ASSEMBLY_VERSION "9.0.30729.1" #else #define _CRT_ASSEMBLY_VERSION "9.0.21022.8" #endif #endif #ifndef __LIBRARIES_ASSEMBLY_NAME_PREFIX #define __LIBRARIES_ASSEMBLY_NAME_PREFIX "Microsoft.VC90" #endif |
1 |
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1 |
1 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Winners |
Opening the executable in Dependency Walker reveals something unusual though: the C run-time DLL being loaded is:
1 |
c:\windows\winsxs\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_5090ab56bcba71c2\MSVCR90.DLL |
Its version is 9.0.30729.4148 (found directly after the public key value encoded in the above path). This is higher than was specified in the manifest! Both versions (and older ones) are installed on my system, so why is the loader choosing a different version? The answer lies in the Winners key for this particular assembly (notice the directory and key name have different values after 'none'):
1 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Winners\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_none_ea33c8f0b247cd77\9.0 |
There are three REG_BINARY values present, each with a value of 01 (meaning enabled; 00 means disabled).
- 9.0.21022.8
- 9.0.30729.1
- 9.0.30729.4148
Therefore as the highest version (9.0.30729.4148) is registered as an enabled Winner, the loader automatically picks it, regardless of the version in the manifest. In a way it makes sense, as if you distribute an application linked to an older version of the assembly that you don't have installed (let's assume you have only the latest version of everything) it would be nice if it still worked off the bat, and didn't require you downloading that specific version of the assembly. Therefore backward compatibility is maintained (and we all know that Microsoft prides itself on this).
The funny thing is that if we made up a non-existent version (e.g. I tried 9.0.30729.0) and specified this using _CRT_ASSEMBLY_VERSION, that version would appear in the manifest. Despite this, the loader would still pick the highest Winner and use that, so the application will still run! However, if there is no enabled Winner with a version higher than the one specified, the application will not run and you'll see the usual “This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.” error message.