Deploying Visual C++ Runtime Files as Private Assemblies
If you create a C++ project in Visual Studio and configure it to “Use MFC in a Shared DLL” (the default) you need to make sure the C runtime (CRT) and the MFC libraries are installed in the correct versions on the end user’s computer. That can be difficult.
There are three ways to install the libraries on target computers. In this article I focus on the “private assembly” method where the libraries are stored in your application’s directory. Some of its advantages are that you can run the program from any location, even a network share, without installing parts of it to the user’s SxS folder first. And you need not worry about calling VC_Redist from your setup.
What you do is simple:
Locate the appropriate folders in C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\x86\ (or AMD64 if you build a 64-bit version). In many cases, when using the runtime and MFC you need Microsoft.VC90.CRT and Microsoft.VC90.MFC. Copy these folders to you application’s binary folder, for example:
C:\MyAppFolder\Application.exe
C:\MyAppFolder\Microsoft.VC90.CRT
C:\MyAppFolder\Microsoft.VC90.MFC
That is all. Redistribute/install your application like this.
Caveats
Your executable’s manifest (incorporated into your EXE file as a resource) lists the versions of the runtime libraries it requires. The versions listed in the manifest are the initial versions installed on your development machine, though. In the case of Visual Studio 2008 these are the versions of the pre-SP1 libraries. Once you install Service Pack 1 you get the newer libraries in the folder C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\x86, but the manifest in your own binary still demands the original library versions.
That does not work. In fact, it crashes your application when run on a “clean” system.
What you need to do is tell the compiler you want to depend on the newest versions of the libraries. You do that by including the following lines at the very top of Stdafx.h of every binary:
#define _BIND_TO_CURRENT_CRT_VERSION 1
#define _BIND_TO_CURRENT_ATL_VERSION 1
#define _BIND_TO_CURRENT_MFC_VERSION 1
#define _BIND_TO_CURRENT_OPENMP_VERSION 1
or, a combination of all these:
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1
Please note: “Generated files (eg by MIDL) don’t include stdafx.h, so putting _BIND_TO_CURRENT_VCLIBS_VERSION in stdafx won’t work in this case. You must use _BIND_TO_CURRENT_VCLIBS_VERSION=1 in the C/C++ Preprocessor Definitions page of every project configuration.” (Jon Baggott on http://msdn.microsoft.com/en-us/library/cc664727.aspx)
Updates, Patches and Service Packs
You may wonder what happens if you happily install the most current libraries on your users’s computers and, some time later, an updated version is released by Microsoft. Will your application continue to use the then old and insecure version? Good question!
If a new version of the runtime library is pushed down via Windows Update and installed to %Windir%\WinSxS, not only are the library binaries and their manifest updated, but also a policy file is installed that basically tells the loader to use the new version instead of the old version. See this example (from %Windir%\WinSxS\Manifests\x86_policy.9.0.microsoft.vc90.mfc_1fc8b3b9a1e18e3b_9.0.30729.1_none_7dd1e0ebd6590e0b.manifest):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation. All rights reserved. -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32-policy" name="policy.9.0.Microsoft.VC90.MFC" version="9.0.30729.1" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.MFC" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<bindingRedirect oldVersion="9.0.20718.0-9.0.21022.8" newVersion="9.0.30729.1"/>
<bindingRedirect oldVersion="9.0.30201.0-9.0.30729.1" newVersion="9.0.30729.1"/>
</dependentAssembly>
</dependency>
</assembly>
This tells the loader to use the version 9.0.30729.1 instead of the versions 9.0.20718.0 and 9.0.30201.0.
Nice, but how does this affect your application with its private assemblies (not tied to the WinSxS folder)? Simple, but effective solution: the loader always looks into the WinSxS folder first. So if your application needs mfc90.dll in version 9.0.30201.0 and version 9.0.30201.0 is what you have installed in your application folder, with the help of the policy file above Windows will load the newer version from SxS nevertheless.
For the sake of completeness here is simplest form of the assembly search sequence:
- Side-by-side searches the WinSxS folder.
- <appdir>\<assemblyname>.DLL
- <appdir>\<assemblyname>.manifest
- <appdir>\<assemblyname>\<assemblyname>.DLL
- <appdir>\<assemblyname>\<assemblyname>.manifest
And for those who still question the use of private assemblies: here is a list of products installed on my system that use them:
- C:\Program Files (x86)\Citrix\ICA Client\msvcm80.dll
- C:\Program Files (x86)\McAfee\Common Framework\Microsoft.VC80.CRT\msvcm80.dll
- C:\Program Files (x86)\TechSmith\Camtasia Studio 6\Microsoft.VC90.CRT\msvcm90.dll
- C:\Program Files (x86)\VMware\VMware Workstation\Resources\msvcm80.dll
And if we take a last look, at, for example, Camtasia Studio: its private version of msvcm90.dll is 9.0.21022.8, but when we examine its loaded DLLs in Process Explorer, we see it uses 9.0.30729.4926 from WinSxS. Magic!
Addendum: Application Crashes at Startup Because MSVCR90.DLL is Not Found
Some time after implementing the solution described in this article for a medium-sized project I was made aware of a strange problem: on some machines the application crashes while loading before even being able to display any messages.
The usual debugging tools sxstrace and fuslogvw (Fusion log viewer) did not show anything useful, but Dependency Walker was helpful. It pointed out the problem right away:
Note: CoreFunctions.dll is one of the DLLs of our product. It is dependent on the Visual C runtime files (including msvcr90.dll) and msvcr90.dll is located in the subfolder Microsoft.VC90.CRT as described in this article. But still, msvcr90.dll is not found by the OS loader.
After some research I found out that this happens both on XP (SP3) and Vista (SP2) if and only if the application is started from a mapped network drive. Copying the application’s folder to the local hard drive makes the problem go away. Another way to fix this is to put the VC runtime libraries directly into the application folder, not in the subdirectory Microsoft.VC90.CRT.
Addendum 2: Application Crashes at Startup Because of Conflicts in the Manifest
A year after writing this article we had a case where our application failed to start and the following event was logged in the application log:
Activation context generation failed for “C:\Program Files (x86)\sepago\Profile Migrator\CoreFunctions.dll”.Error in manifest or policy file “” on line . A component version required by the application conflicts with another component version already active. Conflicting components are:. Component 1: C:\Program Files (x86)\sepago\Profile Migrator\Microsoft.VC90.MFC.MANIFEST. Component 2: C:\Windows\WinSxS\manifests\x86_microsoft.vc90.mfc_1fc8b3b9a1e18e3b_9.0.30729.4148_none_4bf5400abf9d60b7.manifest.
As it turned out this message is logged if there are conflicting entries in the manifest. The easiest way to check is to open the component causing the error, CoreFunctions.dll in this case, in a text editor and scroll to the bottom where the manifest is stored:
Interestingly, this happened only on one developer’s machine. Checking out a fresh copy of the solution from version control resolved the issue, as did deleting the autogenereated solution files, like .suo or the Release directory. Unfortunately we did not find out what really caused this.
References
MSDN: Troubleshooting C/C++ Isolated Applications and Side-by-side Assemblies
MSDN: Assembly Searching Sequence
MSDN: Redistributing an Application and Binding It to Specific Libraries
MSDN blog “Developer Support Languages – VC++, C# and VB.NET”: Part 2: Troubleshooting VC++ Side by Side Problems
7 Comments
thank you for you to make me learn more,thank you???
Hi. Thanks. this issue is driving me nuts. Rather than using this method:
#define _BIND_TO_CURRENT_CRT_VERSION 1
#define _BIND_TO_CURRENT_ATL_VERSION 1
#define _BIND_TO_CURRENT_MFC_VERSION 1
#define _BIND_TO_CURRENT_OPENMP_VERSION 1
Can I use a *.exe.config file like:
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<configuration>
<windows>
<assemblyBinding xmlns=”urn:schemas-microsoft-com:asm.v1″>
<assemblyIdentity
name=”Pando.PMB”
processorArchitecture=”x86″
version=”1.0.0.0″ type=”win32″/>
<dependentAssembly>
<assemblyIdentity type=”win32″
name=”Microsoft.VC90.CRT”
processorArchitecture=”x86″
publicKeyToken=”1fc8b3b9a1e18e3b”/>
<bindingRedirect
oldVersion=”9.0.0.0-9.65535.65535.65535″
newVersion=”9.0.30729.1″/>
</dependentAssembly>
</assemblyBinding>
</windows>
</configuration>
Sounds like a good idea. Does it work?
“Unfortunately we did not find out what really caused this.”
…but I know :-)
When inkremental linking is enabled, and one compiles file1.cpp with old vc libs, then install the new vc libs.
If you now edit another file2.cpp and link both together, VC++ generates a manifest containing both old and new versions.
This happend to us also, but caused no problems. We just had to deploy the newest vc libs to the customers (we use winsxs deployment).
Regards, Mike
Hi Helge,
This article was rally helpful to me. but I have to ask one question. my Unmanaged VC++ MFC (no .net used, no CLR) application properly running on windows 7 fresh installed computer. but I gives “This application has requested the runtime to terminate it in an unusual way” error in wondows XP sp3 computer. In both way I deployed visual C++ runtime files as private assemblies.
This is what you mentioned,
Nice, but how does this affect your application with its private assemblies (not tied to the WinSxS folder)? Simple, but effective solution: the loader always looks into the WinSxS folder first. So if your application needs mfc90.dll in version 9.0.30201.0 and version 9.0.30201.0 is what you have installed in your application folder, with the help of the policy file above Windows will load the newer version from SxS nevertheless.
What if WinSxS doesn’t contain required assembly? It should load private assembly from application directory, right?
I tried to test this. I renamed shared assemblies from WinSxS temporarily and hoped that OS will load private assemblies, but it didn’ happen ans I got various error when I tried to run application exe as shown below
“The program can’t start because MFC80.DLL is missing from your computer. Try reinstalling the program to fix this problem.”
Another error was,
SXS: Unable to resolve storage root for assembly directory amd64_microsoft.vc80.mfc_1fc8b3b9a1e18e3b_8.0.50727.4027_none_84417f7f329478cb in 2 tries
SXS: RtlGetAssemblyStorageRoot() unable to resolve storage map entry. Status = 0xc0150004
Thank you so much! I installed my app on a clean vm. It didn’t start with a side by side mismatch. I started digging into manifests, Win SxS etc., which I had no idea about. After some extensive and useless googling, I found your article that in 5 minutes explained it all brilliantly. Naturally, the problem I had was fixed momentarily. Thank you!