A solution to two references to different versions of CRT, MFC, ATL in one application manifest file
I have received several questions about a case when developers find two or more references to different versions of CRT or MFC or ALT libraries in application manifest. Usually application manifest would look similar to the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50608.0" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
Notice underlined version of assembly. This manifest tells Windows loader to load two different versions of the same assembly. The loader is going to do what it is told to. But the problem arises when it can only find one version (50608) of them. There are two cases when this may happen:
1) The oldest version of VC++ library is installed in WinSxS folder. For example, author of the application may have redistributed VS2005 RTM version of CRT library using MSMs or VCRedist.EXE, but ones parts of application were rebuilt with VS2005 SP1 and deployed to the same machine, SP1 versions of MSMs or VCRedist.EXE were not deployed to the same machine.
2) It is not possible to have two versions of a private assembly in one folder. For example, an author of an application has deployed the RTM version of CRT library as a private assembly in application’s local folder. After application is rebuilt with SP1, the author faces a challenge of having two copies of same files/folders in application local folder. If she keeps RTM version, Windows loader is going to complain about SP1 version missing. If she keeps SP1 version, Windows loaders is going to fail to find RTM version. Windows shows a message box which says :”The application has failed to start because of side-by-side configuration is incorrect,” and event viewer shows error details similar to “Activation context generation failed for "…\foo.exe".Error in manifest or policy file. A component version required by the application conflicts with another component version already active.” Bottom line, application does not start.
The root cause of the issue is that not all parts of application’s source code are built with the same version of VC++ libraries and tools. The linker catches some cases and reports errors when it tries to link objects and libraries built with different versions of compiler. However it is still possible to get pass the linker and an application may get these two dependencies in its manifest.
There is one solution to the problem and two workarounds.
The solution. To fix the problem, you must rebuild all parts of your code with the newest toolset and libraries. Make sure you have cleaned up all binaries built by the old toolset and started full rebuild of the whole source base. Also check that old versions of headers and import libraries for VC++ libraries are not on INCLUDE and LIB path and they are not used during the build.
If you cannot rebuild all your code and use one version of VC libraries, there are two ways to work around this problem:
Workaround#1: Install the newer version (8.0.50727.762 in this case) of VC++ MSMs or VCRedist.EXE on a machine where your application is going to run. Once policy for VC++ assemblies is installed on that machine they are going to redirect all loads of older versions (8.0.50608.0) to the newest version available on the machine.
Workaround#2: If you are redistributing VC++ libraries in application’s local folder, you need to add an application configuration file that redirects an attempt to load 8.0.50608.0 version to 8.0.50727.762 version. Configuration file has to have same name as the exe plus .config extension and has to be right next to exe or embedded into the EXE. Here is an example of a configuration file that one would use to resolve issue with the manifest from above:
<configuration>
<windows>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC80.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
<bindingRedirect oldVersion="8.0.41204.256-8.0.50727.762" newVersion="8.0.50727.762"/>
</dependentAssembly>
</assemblyBinding>
</windows>
</configuration>
This file basically redirects attempts to load any version of VC CRT greater or equal to 8.0.41204.256 (VS2005 Beta 1) and less than 8.0.50727.762(VS2005 SP1) to load VS2005 SP1 version of VC CRT. It is similar to what the policy file does for a case when CRT is installed into WinSxS folder.
Overall my recommendation is to never use static libraries for which you do not have a source code. Using a static library without its source always puts a set of restrictions on build configuration of a binary that consumes it. There are ways to build a “clean” static library, but they are not well known among developers and it is very rare to find a static library that can be consumed in a code built with different versions of compiler, linker and libraries. If source code is not provided, I would only take a dependency on a DLL and only if its APIs are cleanly designed to obey rules of data exchange across DLL boundary. COM and .Net class assemblies are designed to address this problem and they are the easiest technologies to use in this scenario.
Comments
Anonymous
March 29, 2007
When VS2005 SP1 has been released, because of manifests it become more visible what version of VC++ DLLsAnonymous
March 29, 2007
The comment has been removedAnonymous
March 30, 2007
Norman, If an application is built with VS2005 RTM, 50608.0 version is embedded into application manifest. At runtime it is redirected to 50727.42 version by publisher policy. If you deploy VC DLLs in applocal folder manifests in vcredist folder will match version to 50608.0. I think only Debug DLL for OpenMP was not matching that version because of bug. This is common to all VC libraries. For applications parts of which are built with RTM and parts with SP1 versions of VS2005, only SP1 versions should be installed. Both parts are going to load SP1 version and because it is binary compatible with RTM version. It is true that if DLL exposes complex CRT or MFC or STL type in its exports, it may put restrictions on build configuration of a consumer EXE. However this is a design issue. Only simple built-in types can be used in DLL exports. NikolaAnonymous
April 02, 2007
The comment has been removedAnonymous
April 02, 2007
Hi Nikola! I disagree that is is necessary that all static libs must be created with the same compiler version. In this case I mean the different versions of VS2005! Not older versions! There is a simple trick to get around the messy with the injected manifest statements! If the programmer defines _CRT_NOFORCE_MANIFEST in the static library and the main program is created with the any VS2005 compiler and linker and the usual CRT settings are set, than no multiple CRT versions are requested. I wrote already an article about this in my blog in German :-) http://blog.m-ri.de/index.php/2007/03/22/warum-man-seine-libraries-mit-_crt_noforce_manifest-erzeugen-sollte/ Martin MVP C++Anonymous
April 03, 2007
Hi Martin, I did mention in the post that there are ways to build a “clean” static library, but they are not well known and not documented. And I have mentioned that in my post with Q&A about VS2005 SP1. Techniques of using _CRT_NOFORCE_MANIFEST and other non-documented #defines for other libraries may help to remove dependency on a version of VC library from a static library. However it is not documented configuration and almost none is using it. And because there is a very small number of static libraries that use *_NOFORCE_manifest, using a static library is problematic if its source code is not available. NikolaAnonymous
April 10, 2007
The comment has been removedAnonymous
April 24, 2007
The comment has been removedAnonymous
May 10, 2007
The comment has been removedAnonymous
May 10, 2007
Raj, You analysis is right. VC MSMs use different ways of installing DLLs into WinSxS folder for WinXP/Win2k3 and Vista. We are working around a bug in WinSxS folder on WinXP. On Vista, MSMs are using the native MSI support for installing Win32 assemblies into WinSxS store. Native MSI support for Win32 assembly installs uses a 2-phase commit and assemblies are not available until the commit process has completed. Custom actions that rely upon a global assembly must be either of type commit or immediate custom actions sequenced after InstallFinalize or statically link to VC libraries. Services that rely upon the assembly cannot be started using the ServiceControl table. They must be started using a commit custom action or an immediate custom action sequenced after InstallFinalize. Check out MSDN documentation for the ServiceControl table http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/servicecontrol_table.asp and MsiAssembly table docs http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiassembly_table.asp and commit custom action type can be found http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/custom_action_in_script_execution_options.asp. Check out also Custom Action Guidelines on Heath’s blog, http://blogs.msdn.com/heaths/archive/2007/04/20/custom-action-guidelines.aspx. Thanks, NikolaAnonymous
May 10, 2007
Now thats a fast response if there is one!! But you do realize what a problem this can be right? I just moved all my custom actions to before installfinalize to get around UAC issues (These custom actions need to modify systemwide settings, so need to be deferred actions in system context ). If I move it later after installfinalize , the installs will fail if the installs are being done by Local Administrator Group Members and not Domain/Local Admins. If I understand correctly, If I wrote a service which requires global assembly (in my case this is a problem I dont think I have), you have to pick one of 2 -- a) Lose the ability to work within UAC (ie Members of local domain admins cannot install your app) or b) Have the user install VCRTRedist_archtype.exe seperately (or do this from an install bootstrapper outside the msi package ) It is unfortunate that this had to happen on Vista. As a developer, I understand that the rules get stricter on Vista and I am willing to work with that, but when msi, VC2005 SP1 and UAC rules mix, that leaves no room for me :-( In my case I am taking option b), Install the exe external to my msi. Is there an accurate (or recommended) way of determining if a customer has already installed this app, so that I don't end up prompting the user to install it again?Anonymous
May 10, 2007
Raj, If you need to run CAs before InstallFinalize, you may need to install VCRedist.exe upfront, for example, using a simple bootstrapper, or you may statically link these CAs to VC libraries. Check with MSI team,http://blogs.msdn.com/windows_installer_team, and/or Aaron,http://blogs.msdn.com/astebner/, and Heath,http://blogs.msdn.com/heaths/. They may help you find another MSI supported way of building your MSI. NikolaAnonymous
May 14, 2007
The comment has been removedAnonymous
May 21, 2007
The comment has been removedAnonymous
May 23, 2007
Has someone tried #2 succesfully?Anonymous
May 25, 2007
Let me add a little twist on the topic. I'm working on a set of closely related applications that are dependent to an extend on each other. I tried building all of them debug, so I can step through them if any bugs occur. (Compile server runs Win Server 03, my desktop runs XP Pro). As in your example, my code depends on multiple versions of CRT and MFC but the twist is that the debug versions of those dlls are not redistributable. They are not included in vcredist_xx.exe, so I tried deploying them as private assemblies, but I ran into the problem Nikola mentions of having two identically named files in the same folder. Even though you can have private assemblies in subfolder that has the name of the assembly or the locale of the assembly, that did not help me much since they were identical. Copying the assemblies from the winsxs folder of the server to mine did not work either, as shared assemblies must be registered in the registry. (Manual registry editing anyone ??) Now, it seems I will be able to resolve the different version problem (Thanks Nikola !) but what about the debug problem ? Should I move to release versions, or is there any workaround ??Anonymous
May 27, 2007
I think Ventsy Velev's problem can be helped a bit. On the desktop machine, install Visual Studio 2005 even though you won't use it there. Install the debug versions of the CRT and MFC. I wonder if Visual Studio's installer will allow installing runtimes only without installing the compilers and IDE. If so, that will be even better, right?Anonymous
June 24, 2007
The comment has been removedAnonymous
July 09, 2007
Here's how to apply the workaround#2 to the dlls: http://tydbits.com/Application-Configuration-Files-for-dllsAnonymous
September 05, 2007
The comment has been removedAnonymous
December 12, 2007
Just to fill-in the gap: to make workaround#2 work with DLLs, set the name of the config file as follows: <DLL_NAME>.dll.2.config Thanks for everything Nikola! LuisAnonymous
January 17, 2008
Good ,I think os ! Tthanks Martin and Nikola , your discussion has value very much For a C++ member ,who used VS2005 Develop produce . Defined _CRT_NOFORCE_MANIFEST macor can deal this program With different version of CRT ,and this defined in Microsoft Static Libaray crtdefs.h .Anonymous
May 28, 2008
Is there a special work-around for Vista? Simply adding a app.exe.config file in the app folder doesn't seem to work.. only on XP?Anonymous
August 07, 2008
Troubleshooting side by side problems is a not challenging task unless you break the basic checks required