+28  A: 

I have battled this problem myself last week and consider myself somewhat of an expert now ;)

I'm 99% sure that not all dlls and static libraries were recompiled with the SP1 version. You need to put

#define _BIND_TO_CURRENT_MFC_VERSION 1
#define _BIND_TO_CURRENT_CRT_VERSION 1

into every project you're using. For every project of a real-world size, it's very easy to forget some small lib that wasn't recompiled.

Then, check what the embedded manifest says. Download XM Resource Editor: http://www.wilsonc.demon.co.uk/d10resourceeditor.htm. Open every dll and exe in your solution. Look under 'XP Theme Manifest'. Check that the 'version' attribute on the right-hand side is '9.0.30729.1'. If it's '9.0.21022', some static library is pulling in the manifest for the old version.

What I found is that in many cases, both versions were included in the manifest. This means that some libraries use the sp1 version and others don't.

A great way to debug which libraries don't have the preprocessor directives set: temporarily modify your platform headers so that compilation stops when it tries to embed the old manifest. Open C:\Program Files\Microsoft Visual Studio 9.0\VC\crt\include\crtassem.h. Search for the '21022' string. In that define, put something invalid (change 'define' to 'blehbleh' or so). This way, when you're compiling a project where the _BIND_TO_CURRENT_CRT_VERSION preprocessor flag is not set, your compilation will stop and you'll know that you need to add them or made sure that it's applied everywhere.

Also make sure to use Dependency Walker so that you know what dlls are being pulled in. It's easiest to install a fresh Windows XP copy with no updates (only SP2) on a virtual machine. This way you know for sure that there is nothing in the SxS folder that is being used instead of the side-by-side dlls that you supplied.

Roel
Depends never showed what was missing on my clean VM (might need to make sure I've got the latest version!), but using the Resource Editor, I found the offending DLL. It was a DLL we compile but that is not part of our project. Thanks for the help.
crashmstr
I got the newer version of Dependency Walker, and it called out problems immediately with the specific DLLs that were a problem.
crashmstr
The flag _BIND_TO_CURRENT_VCLIBS_VERSION also works.
Dimitri C.
+3  A: 

I just remembered another trick that I used to find out which static libraries were ill-behaving: 'grep' through the static libraries for the string '21022'. HOWEVER, don't use the 'normal' grep tools like wingrep because they won't show you these strings (they think it's a binary file and look for the raw, non-unicode string). Use the 'strings' utility from the resource kit (now in the Russinovich site I think). That one will grep through binaries ok. So you let this 'strings' go through your whole source tree and you'll see the binary files (dlls and static libraries) that contain references to the wrong manifest (or to the manifest with the wrong version in it).

Roel
+2  A: 

Thank you! This helped fix the problems I was seeing.

http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/867cf808-bf1f-4f4a-bde1-cd75d92d73ad

Cameron Taggart
+2  A: 

For your third option, you can probably find the DLLs and manifests for the 9.0.21022 version in the C:\WINDOWS\WinSxS directory on your dev machine. If you can, then you can setup your own redist directory and install those files with your app.

Alternatively, you can use the 9.0.30729.1 ones supplied with Visual Studio and forge the manifest you install with your app to report that it supplies the 9.0.21022 DLLs, and not 9.0.30729.1. The runtime linker doesn't seem to mind. See this blog, which has been immensely helpful for solving these problems, for more information.

Both workarounds fixed the problems I had with deploying the DLLs as private assemblies with VS2008 Express.

Roel's answer is the way to go for your first option ("fix it right"), but if you depend on a library that depends on 9.0.21022 (and your manifest therefore lists both versions), then the third option may be the only way to go if you don't want to run vcredist_x86.exe.

remicles2
+2  A: 

Another nice tool for viewing exe and dll manifests is Manifest View, which fittingly enough will not run on a clean install of XP, because it depends on 9.0.21022.

remicles2
+5  A: 

To understand the problem, I think it is important to realize that there are four version numbers involved:

  • (A) The version of the VC header files to which the .exe is compiled.
  • (B) The version of the manifest file that is embedded in the resources section of that .exe. By default, this manifest file is automatically generated by Visual Studio.
  • (C) The version of the VC .DLLs (part of the side-by-side assembly) you copy in the same directory as the .exe.
  • (D) The version of the VC manifest files (part of the side-by-side assembly) you copy in the same directory as the .exe.

There are two versions of the VC 2008 DLL's in the running:

  • v1: 9.0.21022.8
  • v2: 9.0.30729.4148

For clarity, I'll use the v1/v2 notation. The following table shows a number of possible situations:

Situation | .exe (A) | embedded manifest (B) | VC DLLs (C) | VC manifests (D)
-----------------------------------------------------------------------------
1         | v2       | v1                    | v1          | v1         
2         | v2       | v1                    | v2          | v2          
3         | v2       | v1                    | v2          | v1
4         | v2       | v2                    | v2          | v2

The results of these situations when running the .exe on a clean Vista SP1 installation are:

  • Situation 1: a popup is shown, saying: "The procedure entry point XYZXYZ could not be located in the dynamic link library".

  • Situation 2: nothing seems to happen when running the .exe, but the following event is logged in Windows' "Event Viewer / Application log":

    Activation context generation failed for "C:\Path\file.exe".Error in manifest or policy file "C:\Path\Microsoft.VC90.CRT.MANIFEST" on line 4. Component identity found in manifest does not match the identity of the component requested. Reference is Microsoft.VC90.CRT,processorArchitecture="x86",publicKeyToken="1fc8b3b9a1e18e3b",type="win32",version="9.0.21022.8". Definition is Microsoft

  • Situation 3: everything seems to work fine. This is remicles2's solution.

  • Situation 4: this is how it should be done. Regrettably, as Roel indicates, it can be rather hard to implement.

Now, my situation (and I think it is the same as crashmstr's) is nr 1. The problem is that Visual Studio for one reason or another generates client code (A) for v2, but for one reason or another, generates a v1 manifest file (B). I have no idea where version (A) can be configured.

Note that this whole explanation is still in the context of private assemblies.

Update: finally I start to understand what is going on. Apparently, Visual Studio generates client code (A) for v2 by default, contrary to what I've read on some Microsoft blogs. The _BIND_TO_CURRENT_VCLIBS_VERSION flag only selects the version in the generated manifest file (B), but this version will be ignored when running the application.

Conclusion

An .exe that is compiled by Visual Studio 2008 links to the newest versions of the VC90 DLLs by default. You can use the _BIND_TO_CURRENT_VCLIBS_VERSION flag to control which version of the VC90 libraries will be generated in the manifest file. This indeed avoids situation 2 where you get the error message "manifest does not match the identity of the component requested". It also explains why situation 3 works fine, as even without the _BIND_TO_CURRENT_VCLIBS_VERSION flag the application is linked to the newest versions of the VC DLLs.

The situation is even weirder with public side-by-side assemblies, where vcredist was run, putting the VC 9.0 DLLs in the Windows SxS directory. Even if the .exe's manifest file states that the old versions of the DLLs should be used (this is the case when the _BIND_TO_CURRENT_VCLIBS_VERSION flag is not set), Windows ignores this version number by default! Instead, Windows will use a newer version if present on the system, except when an "application configuration file" is used.

Am I the only one who thinks this is confusing?

So in summary:

  • For private assemblies, use the _BIND_TO_CURRENT_VCLIBS_VERSION flag in the .exe's project and all dependent .lib projects.
  • For public assemblies, this is not required, as Windows will automatically select the correct version of the .DLLs from the SxS directory.
Dimitri C.