This is true madness. In the process of bringing a legacy VC++ project up to date with Visual Studio 2008 there were some real hurdles to get over.
The biggest issue is that starting with Visual Studio 2005 Microsoft introduced the idea of Side-by-Side Assemblies and Manifests. This is a mechanism whereby different versions of the Visual Studio C runtime, ATL libraries, MFC libraries and other assemblies can be run "side-by-side".
So, while your program may compile and run in debug, it may not be able to be copied to a system with no dev environment on it without serious tap-dancing. You'll get cryptic "The application is not configured correctly and should be reinstalled" messages on XP or a vague hint about SxS on Vista.
After a lot of time spent on the MSDN forums I finally figured out how this mess works.
First off, VC++ apps will include \Program Files\Microsoft Visual Studio 9.0\VC\include\crtdefs.h via Stdafx.h. Look at this header file. It contains lines like this:
#include <crtassem.h>
#ifdef _M_IX86
#ifdef _DEBUG
#pragma comment(linker,"/manifestdependency:\"type='win32' " \
"name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugCRT' " \
"version='" _CRT_ASSEMBLY_VERSION "' " \
"processorArchitecture='x86' " \
"publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' " \
"name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \
"version='" _CRT_ASSEMBLY_VERSION "' " \
"processorArchitecture='x86' " \
"publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#endif
#endif /* _M_IX86 */
This will put a little piece of code in the .obj which gets picked up by the linker and the manifest tool. So, if _DEBUG if defined anywhere, you'll get manifest entries requiring the debug runtimes. So, double/triple check that you don't have any debug files or .libs in your project. The .manifest file looks like this:
<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.30729.4148'" processorarchitecture="'x86'" publickeytoken="'1fc8b3b9a1e18e3b'">
</assemblyidentity>
</dependentassembly>
</dependency>
<dependency>
<dependentassembly>
<assemblyidentity type="'win32'" name="'Microsoft.VC90.MFC'" version="'9.0.30729.4148'" processorarchitecture="'x86'" publickeytoken="'1fc8b3b9a1e18e3b'">
</assemblyidentity>
</dependentassembly>
</dependency>
</assembly>
The big thing to note is the version of the runtime. How does Visual Studio know which version of the runtime to load? Well, it uses \Program Files\Microsoft Visual Studio 9.0\VC\include\crtassess.h to make this decision. Whenever you install a new Service Pack for Visual Studio this file gets updated.
If you define _BIND_TO_CURRENT_VCLIBS_VERSION = 1 in your C++ code, crtassess.h will grab the latest MFC, ATL and CRT libraries, whatever they are. These are the versions that will go into the .manifest file (by the way, set up your code to embed the .manifest in your code to keep things easier).
On the deployment machine, you need to install all the Visual Studio runtime libraries. The best way to do this is by running the latest and greatest vcredist_x86.exe application from the microsoft site. But this has its own problems.
The entire version number of the assembly is important. With VS 2008 SP1, the CRT version was bumped from 9.0.21022.8 to 9.0.30729.4148, but the redist for SP1 installed 9.0.30729.1 and the program wouldn't run on the deployment machine. Turns out there was a Security Update for SP1 and a later redist program for it. I don't know how you're supposed to keep up on this other than watch the msdn forums. Once this was run on the deployment machine the program would run.
Another problem I ran into was the compiler kept putting entries in the manifest for the older 9.0.21022.8 crt even though I had _BIND_TO_CURRENT_VCLIBS_VERSION defined everywhere. The workaround for this is very cryptic. You need to put the following code somewhere in your application (like in stdafx.h)
extern "C" {
__declspec(selectany) int _forceCRTManifestRTM;
__declspec(selectany) int _forceCRTManifestCUR;
};
This will force the compiler to use the latest assemblies.
You can see how the manifests are looked up on your deployment machines by looking in \Windows\WinSxs. You'll see the mapping of the runtime to the .dll's along with the security policies for selecting them. Using this you can quickly spot any discrepancies between your development environment and your deployment environment.