Friday, June 08, 2007

Manifest hell

I thought Manifests were an end to DLL hell - but it just seems that now we have manifest hell


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:



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:
inferior and superior char have been replace by { and } because google blogs text editor is retarded

{configuration}
{windows}
{assemblybinding xmlns="urn:schemas-microsoft-com:asm.v1"}
{dependentassembly}
{assemblyidentity publickeytoken="1fc8b3b9a1e18e3b" processorarchitecture="x86" name="Microsoft.VC80.CRT" type="win32"}{/assemblyidentity}
{bindingredirect newversion="8.0.50727.762" oldversion="8.0.41204.256-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.


http://msdn2.microsoft.com/en-us/library/aa374182.aspx

Visual Studio 2005 SP1
http://www.microsoft.com/downloads/thankyou.aspx?familyId=bb4a75ab-e2d4-4c96-b39d-37baf6b5b1dc&displayLang=en

VCRedist x86
http://www.microsoft.com/downloads/details.aspx?familyid=32bc1bee-a3f9-4c13-9c99-220b62a191ee&displaylang=en

Visual Studio 2005 SP1

Installation fails on Windows Server 2003 editions with Windows Server 2003 SP1 Installed:
loadTOCNode(3, 'moreinformation');
The error reported is
Error 1718. File Filename was rejected by digital signature policy.This problem occurs when the computer has insufficient contiguous memory for Windows Server 2003 or Windows XP to verify that the .msi package or the .msp package is correctly signed.To resolve this issue:

Refer to KB article 925336 (http://support.microsoft.com/kb/925336).

VS2005 SP1 and Microsoft.VC80.CRT in applocal mode

problem running some of our applications in "applocal" mode since we have upgraded to SP1.
We use some external libraries (we don't have the source code) that were compiled with the original VS2005.
The following manifest is therefore generated:













The application runs fine when the CRT in present in WinSxS (the Policy does the correct redirection). However, if you want to use the "applocal" mode for this particular application.

When running "app.exe" if you get this message: "This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.

Choose external manifest

_USE_RTM_VERSION is newly introduced in SP1 (and previously also in hotfix 919280). It is found in crtassem.h and crtdefs.h. If you use _USE_RTM_VERSION - it must be done in all EXEs and DLLs the app uses. The _USE_RTM_VERSION define determines which CRT version is placed in your manifest file. If it is defined, then the old version number is put in.

If not defined, then it puts the new version in (what ever version ends up shipping with SP1)And no, using _USE_RTM_VERSION does not avoid the runtime rebinding to the new version. The fact is, it only gives the apps the ability to use the originals, but if the new ones are there on the machine in WinSxS, then it uses the new ones instead. Without _USE_RTM_VERSION, if the originals are there and the new ones aren't, then the app doesn't even run.Without using WinSxS, even if you install applocal and if same or newer versions exist in WinSxS, then those in WinSxS will be used instead. However, there is one way to trick the system into never using the new ones from WinSxS, and only using your applocal (original) ones.

For more info see http://blog.kalmbachnet.de/?postid=80

I know of no way to force an app to use a specific version out of WinSxS, if a redirection policy has been installed.

No comments: