Managing Manifests and Dependencies Under Visual Studio

When building an executable under Microsoft Visual Studio (either the 2005 or 2008 edition), an accompanying manifest file is generated. The purpose of this file is to describe various dependencies of the executable such as DLLs. The manifest file is typically baked directly into the executable itself, but alternatively it can exist as an external XML file. In externalizing an application’s dependency information, developers can explicitly control which versions of the dependent files are to be used. One major benefit of this design is that various versions of a dependency can exist simultaneously (Side-by-side assemblies as Microsoft calls them) and thus different programs need not use the same version of the dependency files. This is a great idea in theory as it would eliminate the problem of keeping system DLLs in sync, a process affectionately known as DLL Hell. However, there are still a few quirks of manifest files that can drive developers and users alike mad.
For the past few years, I’ve been developing a 2D video game engine called SFII90. The engine was initially developed under Visual Studio 2005 on Windows XP and later migrated to Visual Studio 2008. When the initial release was ready to be deployed, I ran into a few problems running the application on other operating systems (specifically Windows Server 2003). Despite installing the VS2005 redistributable components on these systems, I was greeted with error dialogs similar to the following:

After learning that the problem was due to a misconfiguration regarding the application manifest file, I spent quite some time searching online for suggested resolutions. What I eventually found was that I was suffering from a few issues. Most notably, the manifest file required msvcr80d.dll (the debug version of the C run-time library), although this was not being used by my application nor was it included in the redistributable package (Microsoft only allows release mode binaries to be distributed to users). I used a very helpful tool known as Dependency Walker to verify that the application did not require the debug library:

I could confirm that the application did not rely on the debug CRT library msvcr80d.dll. Regardless, every time I built the application, the manifest listed it as a dependency. I finally realized that the application itself did not require the debug library but that some of its dependents were in fact dependent on the debug library. The project included a few DLLs that I had built from source such as FreeType and Vorbis. These had apparently been built as debug libraries under VS2005. Even after migrating to VS2008, these libraries required the VS2005 debug CRT library which explained why the main application was requesting the debug library. After rebuilding all of the DLLs in release mode under VS2008, the references to msvcrt80.dll in the manifest file disappeared. At that point, my external manifest file “SFII90.exe.manifest” looked like the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
The important part of the manifest file above is where the name of the dependent manifests and their versions are defined. In this case, the name of the sole dependency is “Microsoft.VC90.CRT”, so the accompanying manifest file must be “Microsoft.VC90.CRT.manifest”. This file can typically be found as part of the Windows side-by-side assembly manifests under C:\Windows\winsxs. It is critical that the version of the CRT manifest matches that defined in the main application’s manifest (in this case, the version is 9.0.21022.8). The following illustrates an example of the contents of such a manifest file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<noInheritable></noInheritable>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
<file name="msvcr90.dll" hashalg="SHA1" hash="e0dcdcbfcb452747da530fae6b000d47c8674671"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>KSaO8M0iCtPF6YEr79P1dZsnomY=</dsig:DigestValue></asmv2:hash></file>
<file name="msvcp90.dll" hashalg="SHA1" hash="81efe890e4ef2615c0bb4dda7b94bea177c86ebd"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>ojDmTgpYMFRKJYkPcM6ckpYkWUU=</dsig:DigestValue></asmv2:hash></file>
<file name="msvcm90.dll" hashalg="SHA1" hash="5470081b336abd7b82c6387567a661a729483b04"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>tVogb8kezDre2mXShlIqpp8ErIg=</dsig:DigestValue></asmv2:hash></file>
</assembly>

All of the manifest files and DLLs being referenced should be placed in the same directory as the main application. To summarize, dealing with manifest files is not too difficult, but due to seemingly erroneous dependencies and version incompatibilities, they can be intimidating to configure properly. For this reason, I suggest externalizing the manifest files (this can be done in Microsoft Visual Studio by naviating to Project Properties -> Linker -> Manifest File -> Allow Isolation and setting the value to “Yes”) and resolving dependency issues using Dependency Walker.