This is the source code of an amended version of Vcredist_x86.exe, the redistributable distributed by Microsoft. Microsoft forgot to include the required Windows Installer 3.1 in the redistributable. The above file comes with a bootstrapper that detects if any prerequisites are missing and installs the required runtimes.
This article is also a compilation of the various forum/usenet/message board postings and findings on the topic of C++ deployment in Visual C++ 2005.
This section mostly applies to programs built from the command line (with cl or nmake). Although, you can reproduce the same from the IDE, it requires changing numerous project settings, and if you're doing this, I assume you already know what you're doing!
You've set up the Visual Studio environment and compiler, you've successfully built your project, and now your ready to test your VC++2005 app. However, before it is able to start up, you get an error:
And you want to know what's going on.
Programs compiled with Microsoft Visual C++ that dynamically link to the C runtimes (/MD or /MDd) have to bundle with them a copy of the C-runtime DLLs (usually called MSVCRT.DLL or MSVCRxx.DLL where xx represents the version of Visual C++). If you just copy the .EXEs but forget to copy MSVCRxx.DLL along with it, you'll get the above error.
Okay, you note that MSVCR80.dll isn't located in System32. It is located in another directory (C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.42_x-ww_0de06acd). You copy it from there to System32 (or if you're a veteran from the DLL hell days, you'll know better and copy the DLL to your app directory instead) and you try to run it again:
This error occurs whether you copy it to your application directory or System32. The release build gives you a slightly different error message, but still mostly the same.
Visual Studio 2005 made a number of changes to the way the C-runtime library is linked in. The first change is that the single threaded libraries are now gone. If you need the performance boost that the single threaded libraries provided and are willing to sacrifice thread safety, you should make use of the nolock variants of the CRT library functions. The second change is that projects created with VC2005 IDE now dynamically link to the C-runtime libraries by default. In VC2003, only MFC and managed C++ apps dynamically linked to the CRTs by default.
Finally, the C and C++ runtimes are now implemented as Side-by-Side DLLs. It's no longer enough to copy MSVCR80.DLL/MSVCP80.DLL/MSVCM80.DLL (from now on called the CRT DLLs) into the System32 directory. You must now load the CRT DLLs through a manifest. If you attempt to load the CRT DLLs without using a manifest, the system will detect this, raise an R6034 assertion, and
abort(). That's why the CRT DLLs are now located in WinSXS and not in the System32 directory.
If you go back to the build directory, you will notice that there is a new manifest file called <appname>.exe.manifest (if it's not there, then remove the /MANIFEST:NO switch from the linker command line). You can either copy this manifest to the local directory, or you can embed this as a resource of your executable:
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST helloconsole.exe.manifest
Compile with the rc.exe tool and embed using the linker. Alternatively, you can use the mt.exe tool to create and embed the manifest to the executable:
mt.exe /manifest helloconsole.exe.manifest /outputresource:helloconsole.exe
Once you have embedded a manifest, your build now resembles apps made from the IDE.
(This part applies to builds made in the VS IDE and command line builds that followed the previous section). You've built your app, and now you attempt to run it on your machine. At last your program runs properly:
However, when you try to run on another machine (a machine that does not have Visual C++ installed), you receive this message:
A bit of troubleshooting (Dependency Walker) tells you that it has something to do with the CRT DLLs, but you cannot figure out where to put those darn DLLs. You've copied msvcr80.dll to the System32 directory, the application directory, even the WinSXS directory. It still doesn't work. What's going on?
Now that your app is configured to load the CRTs through a manifest, the CRT DLLs must now be placed in a directory recognized by the side-by-side technology. You can either load the CRT DLLs via a shared side-by-side assembly, or through applocal assemblies. Applocal assemblies are covered in a later section (see below). First, we will cover how to install the CRTs as a shared side-by-side assembly.
If you choose to install a shared side-by-side assembly, they will need to be installed with a Windows Installer setup project (copying doesn't work). The setup will create policies, manifests, and some registry keys to the HKLM registry (the manifests and policies are important for the side-by-side engine to recognize the isolated library).
You cannot use a third party setup to install a shared side-by-side assembly. That part of the setup must be performed by a Windows Installer package. It's bad news if you're using Express Edition (which doesn't have the ability to create setup projects).
For older Windows (Win2K and below), there is no such concept as a side-by-side DLL, and the CRT DLLs will need to be installed either in the System32 directory or the same folder as the application. All this means that you have to create a complicated installer that behaves differently on different operating systems (even the service pack level of the OS can alter the behaviour of your installer).
Fortunately, Microsoft has already written a merge module that does all this for you (including registering the side-by-side DLL). Look in the "\Program Files\Common Files\Merge Modules" to find a set of MSM files (ignore the properties that say it's Beta 2. It actually installs the final release). The files that have "CRT" in their names are the ones you need to redistribute (if you use MFC/ATL, you'll also need the other MSMs). By including these files in your setup project, your setup will properly install the runtime DLLs in the correct location.
If you're not using Windows Installer, you can use the executable located in "\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bootstrapper\Packages\vcredist_x86\vcredist_x86.exe". All you have to do is execute this redistributable in your third party setup.
However, there is a major bug with the current version of the merge modules. Before you install the runtime redistributables you have to ensure the following components are installed first:
|OS||Installable||Required service pack||Other software|
|Windows 98/ME||Yes||Internet Explorer 5.0 required (included in Win98SE/ME)||Windows Installer 2.0 required|
|Windows 2000||Yes||Service Pack 3 required (includes Windows Installer 2.0)||Windows Installer 3.0 required|
|Windows XP||Yes||Service Pack 2 recommended||Windows Installer 3.0 required (included in Service Pack 2)|
|Windows Server 2003||Yes||Service Pack 1 recommended||Windows Installer 3.0 required (Windows Installer 3.1 included in Service pack 1)|
For example, if you're trying to run your app on a Win2K computer, you have to download the latest Windows 2000 service pack (SP4), install that, reboot, then download Windows Installer 3.1, install that and reboot. Then finally, you need to copy the vcredist_x86 file and install that. Such a number of steps (which significantly alters the operating system, requires many reboots, and probably breaks the existing apps) are very inconvenient for an end user. If any one of these components is not present, the merge module will fail with a nondescript error at the end user's expense (I got an error 1723 when testing). This complex install process was a design decision made by Microsoft.
Although there are changes coming for SP1, I couldn't wait for that to be released, so I came up with my own installer that included all the necessary updates in it. And this is the topic of this article.
The code is for a bootstrapper that detects the presence of C-runtimes and if not present, installs them. If either Internet Explorer or Windows Installer needs to be updated, the user is presented with a dialog asking to install them as well. The main components are launched in an interactive mode with the
/norestart switch set to prevent them from rebooting the computer. If you want to change this, you'll need to alter the
InstallRequiredApps() function in my source. You'll also need to download each component separately:
Place all these packages in the same directory as the solution file.
Detecting Internet Explorer is done through checking the value of the "Version" string in HKLM\Software\Microsoft\Internet Explorer. The version of Windows installer is checked by calling the
DllGetVersionInfo export from MSI.DLL. The Windows version is checked through the
GetVersionEx() API. In order to detect if the CRTs are installed, I have created a simple DLL that dynamically links to the C runtimes. If a call to
LoadLibrary() fails for this DLL, we know that the C-runtimes are not installed and should install them.
The bootstrapper's binaries will be compressed with IExpress (the package and deploy wizard bundled with Windows). The IExpress packager works in all 32-bit versions of Windows, checks for binary integrity (e.g. bad downloads), and automatically determines a writable temporary directory (for LUAs). Although, we could implement these features ourselves (that's what earlier editions of this article did), I'd rather make use of externally tested code than attempt to reinvent the wheel.
When you make a bootstrapper application (that needs to run on every OS from NT3.x to Windows Vista), you have to be very careful about which APIs you invoke, and how you run your app (static link only, no shlwapi, no MFC, no internet, no ATL, no .NET, no debug helpers, etc.). Unfortunately, Visual C++ 2005 makes code that is inherently unrunnable in older Windows (it needs
IsDebuggerPresent() to be present in Kernel32.dll). If you want my bootstrapper to run on older Windows OSes (even if it's just a message box telling the user the program cannot run on this OS), you have to use an older compiler, such as VC6.
And that should be it. The return numbers returned by my bootstrapper are:
- 0: if the install succeeded or was not needed.
- 3: if an uncaught exception was thrown (e.g. if a system resource allocation failed), or
abort() was called.
- 192: if the operating system is outdated.
- 1223: if the user cancelled the installation process.
- 1613: if Windows 2000 needs an updated service pack.
- Some other error: The return code for one of the components installs.
If you dynamically link to the MFC DLLs and make use of its data access classes, you'll have to include a whole bunch of redistributables (such as the updated common controls, the MDAC, and DCOM update). And if you use its internet related classes, you'll have to update the version of Internet Explorer. Note that the requirement of IE is only for MFC. If you don't use MFC, you don't need to redistribute Internet Explorer (indeed, if you
#define EXCLUDE_IE60 with my bootstrap, then you can compile a smaller bootstrap that removes the IE-related stuff).
The MFC runtimes themselves will be installed by vcredist_x86.exe, which will also install the ATL and OpenMP runtimes. If you are using the Unicode release of the MFC DLLs, note that the Microsoft provided DLLs will not work on Win9x (since Win9x does not implement Unicode). Please follow the instructions located in Michael Kaplan's blog to see how to rebuild the MFC DLLs to use the MSLU.
If you're running Visual C++ Express, you can still use my bootstrapper application even though you lack the capability of creating a setup project (and you lack the redist folder, and vcredist_x86). Outlined in Nikola Dudar's blog are the steps to compile a CRT MSI from those merge modules which you can redistribute to the end users. The first step is to download and extract the WiX binaries to a folder (actually, the first step is to download and install platform SDK, but you've already done that haven't you?).
Once you have installed WiX (I'll assume you installed it to "C:\WiX"), you need to open up a SDK command prompt. Run the following command twice:
This should give you two GUIDs (one for each time you run uuidgen) which will be useful later on. Memorize those two GUIDs. Now create an XML file called "C:\WiX\vccrt.wxi".
The contents of C:\WiX\vccrt.wxi should look something like this:
Don't save the file now, replace those 0s with the two GUIDs you memorized earlier. Once you have replaced those GUIDs you can save the file (and you can also forget those GUIDs you memorized). Now create a file called C:\WiX\vccrt.wxs and give it the contents:
[Editor comment: Line breaks used to avoid scrolling.]
Name="Visual C++ 8.0 Runtime Setup Package"
Description="MSI to redistribute my app"
Comments="MSI to redistribute my app"
<Directory Id="TARGETDIR" Name="SourceDir">
src="C:\Program Files\Common Files\Merge
<Merge Id="CRT Policy"
src="C:\Program Files\Common Files\Merge
<MergeRef Id="CRT" />
<MergeRef Id="CRT Policy"/>
Now with these two files saved open up a command prompt at C:\WiX, and type in the following commands:
candle.exe vccrt.wxs -out vccrt.wixobj
light.exe vccrt.wixobj -out vccrt.msi
In the end, you should have a file called vccrt.msi. If you're getting any errors, you should check out the troubleshooting section of Nikola's blog. With the vccrt.msi created, run this file on all the machines you intend your app to work on.
If you want my bootstrapper application to invoke vccrt.msi instead of vcredist_x86.exe, you need to alter my code so that the MSI is executed instead (instructions are given in install.txt).
Microsoft offers a number of alternatives for deploying the C runtimes without using a setup project. All of these alternatives allow your VC2005 app to run on another computer.
Assuming your application is called helloconsole.exe, and is installed in C:\test\, you can copy the CRT DLLs to the application folder.
Once you have done that, open up your \Program Files\Microsoft Visual Studio 8\VC\Redist\x86\Microsoft.VC80.CRT folder and look for the file called Microsoft.VC80.CRT.manifest. If you run C++ Express or don't have the redist folder, this is what the Microsoft.VC80.CRT.manifest looks like:
="1.0" ="UTF-8" ="yes"
Save this to a UTF-8 XML file called Microsoft.VC80.CRT.manifest (and make sure the copyright sign comes out correctly).
Once you have the manifest, copy it to the C:\Test\ directory, along with the CRT DLLs and then your application should successfully run. Your directory should now look like:
If you're making use of MFC/ATL/OpenMP, you will also need to copy the corresponding runtimes and their manifests as well (see your redist folder). Now your app should run.
Exercise: what happens when the user (or more accurately, the administrator) subsequently installs the vcredist_x86.exe package after you have copied these "app-local" DLLs? Which version will be loaded?
In earlier versions of this article, I assumed that the applocal DLLs would override the WinSXS DLLs (not desirable if the shared assemblies are a later version of the CRT). To make certain however, let's confirm this by performing some PSAPI tests:
#pragma comment (lib, "psapi")
static const int MAX_MODULES=1024;
DWORD lpcbNeeded = 0;
&names, names.size() * sizeof(HMODULE), &lpcbNeeded))
names.resize(lpcbNeeded / sizeof(HMODULE));
for each(HMODULE item in names)
DWORD charsCopied = GetModuleFileName(item,
std::tcout << TEXT("*") << &module_name
On an XP machine with both applocal and WinSXS DLLs installed, the output looked something like:
This shows that my earlier assumption was wrong. The shared assemblies are indeed loaded in preference to the app-local DLLs. Until the administrator is coerced into installing the shared CRT DLLs, your app can make use of the app-local DLLs. Once the shared CRTs are installed, your app will start using the shared CRT DLLs, and your app local DLLs become unused files. This method has two advantages going for it (no setup required, will run on unpatched Windows 2000/XP/2003 systems), and I cannot find anything else wrong with this approach, I feel that this method offers an attractive solution for making your app run on another computer. Microsoft fully supports this method of deployment, albeit by arranging the CRT DLLs slightly differently.
If you look at your redist folder, you will notice that the files are located in strangely named subdirectories, like Microsoft.VC80.CRT, or Microsoft.VC80.MFC. These directories are purposefully named, because when you install your application, Microsoft recommends you to copy these folders as-is to your application directory.
According to Microsoft your setup should look like this for WinXP and above:
For Win2K and below, it should look like:
(Exercise: How would you arrange the DLLs such that it is the setup for both WinXP and Win2K?)
Not only are you going to need redundant copies of the CRT DLLs, Microsoft admits that this approach only works if your application is an executable (EXE). It does not work for DLLs. For DLLs, Microsoft mandates that you follow a setup similar to the one I've described. However, if my method works for both EXEs and DLLs, why don't we just always arrange the CRT DLLs in the way I've described?
According to Microsoft, installing a private side-by-side assembly is not supported on Windows 2000 and below, but it seems to work okay. They prefer the CRT DLLs to be installed in the System32 directories. In my opinion, it sounds more like scare tactics from Microsoft. They say it may or may not work, but they're not going to help you if you do it.
If you use any part of the CLR (say, you're writing a C++/CLI app), then you have to install the .NET Framework. If this is the case, then you can kill two birds with one stone by just redistributing the .NET Framework. Note that the .NET Framework is a larger redistributable that will refuse to install if you don't have Internet Explorer 6.0, or the latest service pack for Windows 2000 (or XP or 2003 or Vista). Again, you will also require Windows Installer 3.0. However, with the .NET Framework, at least you get a friendlier error message that indicates the missing component (no need for my bootstrapper).
Overall, the end user may have to download 360 MB of patches before they can install the .NET Framework. However, once the .NET Framework is installed the user will probably have nearly everything they need to run the app (including the CRTs, MSIE, latest service pack, MSI 3.0). Everything apart from MFC / ATL / OpenMP libraries - they still need to be redistributed if you use them.
If you have the source code of C runtimes (only available if you do a full install, and you're not on Express Edition), then you can rebuild the entire CRT to get them to behave just the way you want (in this case, load from your own dir). However, there is a legal issue with distributing an application that links to a hacked CRT (make sure you review the VS EULA with your legal team). Most importantly, the name of these rebuilt DLLs must not be called MSVCR80.DLL (or MSVCP80.DLL or MSVCM80.DLL). You might have other reasons to use a custom CRT, (e.g. to enable MSLU support for the CRTs). If that is the case, you should choose this solution. Steps to rebuild the CRT are given in the MSDN site.
Unlike Microsoft's CRT, this private CRT is not supposed to be placed in the WinSXS directory or even the System32 directory - it should be placed in the same directory as your app. The primary difference between your private CRT and Microsoft's CRT is that
_CRT_NOFORCE_MANIFEST is not defined in your build. That means the code that checks if the DLL was loaded via the manifest (which also happens to be the code that prevents your app from running under Windows NT) gets preprocessed out. Thus you can deploy this DLL locally with your app, without needing to include a manifest with it (Windows NT compatibility is an added bonus).
To use the modified CRT, you need to add a /NODEFAULTLIB switch to your linker command line (Project -> Project Properties -> Configuration Properties -> Linker -> Input -> Ignore All Default Libraries, set to Yes). Then, you need to add the full path to your rebuilt CRT in the Additional Dependencies field (as well as any Win32 libs that got excluded). This needs to be repeated for all your projects.
Also note that you will get serious problems if you use a rebuilt CRT, you call into a DLL that expects STL parameters (or a
FILE* or any other CRT-specific construct), and that DLL does not use your modified CRT. Such problems include heap corruptions, unreleased locks, debug asserts and other crashes (i.e. all those crashes which only occurred on the end users' machines but not yours).
The major disadvantage with this approach is that if you're using a buggy function in the CRT DLLs and Microsoft issues a fix for that function, your application will not be updated. The only way you can fix this bug is to patch your version of Visual Studio and rebuild the CRTs again.
The final option is to statically link your executable to the CRT (by the way, this is how the bootstrapper is able to run without the CRTs). To statically link to the executables, go to the Project -> Project Properties -> Configuration Properties -> C/C++ -> Code Generation -> Runtime Library (change from "Multi-Threaded DLL" to "Multi-Threaded").
If you're careful enough, you can even get the application to run on Windows NT! The pieces of the CRT that require
GetLongPathNameW get discarded out of your final executable, and thus your app can run on Windows NT. In order for this to happen, you have to be careful about which C functions you call (no
algorithm), and you'll probably have to upgrade to the latest service pack for Windows NT (plus all post service pack patches).
Using this method is not much better than rebuilding the CRTs. Once again, if your application consists of several DLLs where each DLL expects STL/CRT parameters, you will get serious bugs until you rebuild by dynamically linking the CRT.
And if Microsoft issues a fix for their routines, and you use this method, you become solely responsible for fixing both yours and Microsoft's bugs.
If you have Windows 2000, please consider yourself a tester for my app. I have not tested my bootstrapper on this OS, and some of my most complex code runs specifically on this operating system. If you are on Win2K, please, let me know how it works.
There is a lot of hardcoding going on in my bootstrapper. It's not as configurable as this installer. It does not support the installation of .NET (although it could with a few minor modifications). And currently it only supports one command line option (
/silent), and even this switch doesn't work that well as it should.
My bootstrap behaves rather unreliably if the user chooses to install Microsoft's components, but cancels them in the middle of the install. If you're still receiving errors even after you have deployed your application, then...
If you're getting errors related to MSVCR80D.DLL/MSVCP80D.DLL/MSVCM80D.DLL (note the D), then please recompile your app to be a release build (go to Build -> Configuration Manager and where it says Active Solution Configuration, select "Release"). If you're the end user, ask the application developer to rebuild his program in a release build.
If you're getting some other error related to missing DLLs, then try opening your application under Dependency Walker (it's located somewhere under the Platform SDK folder - search for the depends.exe in the folder where you installed the Platform SDK. If it's not there, then download it from here). Dependency walker should tell you how a DLL is loaded and if any DLL is missing or outdated. Missing DLLs are noted with ? marks and outdated DLLs are flagged red.
If you are receiving a R6034 error, then make sure your app contains a manifest. Then make sure your folder includes a second manifest called Microsoft.VC80.CRT.Manifest (see above). Note that if you're running Windows 95/NT or below, then it's not possible to solve your error unless you upgrade your operating system.
If you are building a DLL and that DLL is having trouble loading, then make sure that DLL has an embedded manifest. The manifest for a DLL should be created with the following command:
mt.exe /manifest helloconsole.dll.manifest /outputresource:helloconsole.dll;#2
DLLs need to have its manifest embedded as a resource with the resource ID equal to 2 (according to MSDN). External manifests do not work for DLLs, they only work for applications, so unless you are able to alter the application's manifest, you should embed the mt.exe generated manifest into your DLL.
One trick that seemed to have solved some problems is to enable the "Use FAT-32 Workaround" setting in project properties. Although Microsoft hasn't revealed what this setting actually does, some users have replied that it solved whatever problems they had.
If you are not receiving a R6034 and Dependency Walker shows nothing wrong, and you've fully patched Windows and it has a supported version of Windows then perhaps it might be a problem related to the DLL itself. Try looking at the links below to see if they are of any help.
Since this article was published, Microsoft has paid attention to the complaints, and in service pack 1 for Visual Studio 2005, they have fixed some of the most pressing concerns with their software. The vcredist_x86.exe no longer requires MSI 3.0 to run, it can now run on machines where the Windows installer version is 2.0. This means the vcredist install sequence becomes relatively simple:
- Run InstMSIA.exe (if MSI2.0 is already installed, this will do nothing)
- Run vcredist_x86.exe (if the CRTs are already installed, this will do nothing)
- Install your application.
You no longer need to check the windows version or service pack level (the table above is no longer relevant). What's more, vcredist_x86.exe will guarantee that the CRT DLLs are installed into the correct locations. This same procedure works for all supported versions of Windows. The fix is available as a QFE if you can't wait for service pack 1 to be released.
- Ted. W
- Nikola Dudar
- Ayman Shoukry
- Martyn Lovell
- Added several missing steps for VC Express users.
- Fixed problems with the WiX steps. Added steps on rebuilding CRT.
- Corrected the location of vcredist_x86.exe.
- Updated article with subsequent information discovered in 2006. Changed the intro to show what happens if you miss some steps. Changed the executable to use IExpress.