Why your application fails to load after building with a new version of VS?
In this blog post I would like to outline how the build decides the CRT dependencies and what that means to the user. This basic trouble shooting guide should come in handy for diagnosing dependency errors. Please note that Nikola’s blog is an awesome source for additional help (http://blogs.msdn.com/nikolad/).
** Where does an application get its fusion dependencies?
Three possible sources:
1) VC Headers:
Each VC library has a <lib>assem.h file (for example, CRT has crtassem.h, MFC has mfcassem.h, etc). Those headers define a linker directive to add a manifest indicating which Win32 assembly must be loaded for your application to work (through a pragma comment(linker…). This definition consists of two parts:
a. Assembly Name: Microsoft.VC90.CRT
b. Assembly Version: 9.0.num.num.
This means that any compilation unit that includes one of those headers will include a linker directive pointing to the version of the VC libs it needs to work properly.
2) VC Libs/User Libs:
A library is a collection of obj files. If those obj files included the VC runtime headers, they will end up with a linker directive pointing to the version of the VC libs they depend on.
When the user links such libs (objs) with his code, linker directives will be honored by the linker and the user will get the dependencies in his final image.
3) A manifest file that is passed to the linker at link time.
** How do I see the final image dependencies?
– You can open the image in DevEnv.exe, and expand it RT_MANIFEST resource.
– You can open the image in notepad.exe, and search for VC90.
– You can use mt.exe to export the manifest as a text file and then open it in notepad.
Usually, you should see only one version of a given library. Seeing the following indicates something might have gone wrong:
a. Both debug lib and retail lib.
b. Version X lib and version Y lib.
** The header defines only one dependency per library – so where did the other dependency came from?
The source for multiple dependencies is linking obj files that were compiled differently. Those objs might have come from
1) your own build
2) from lib files you own or
3) from lib files you pick up from a 3rd party.
One handy way to find the source, is to simply search the libs/objs you link for the unexpected version (you can use VS to do that or even “findstr /is <version number> *” will do). The right version you should end up with is the version defined in your <lib>assem.h. Once you identify the source of the unexpected version, you need to rebuild it (if you own it) or ask for another drop if you pick it up from somebody else.
NEVER attempt changing the dependencies by hand and forcing them to be a certain version. This can lead to extremely hard to debug random crashes. Forcing dependencies to be the same by changing them by hand is ignoring the differences between different versions of the library you are using. Those differences can (and will) include binary incompatibilities (different object sizes, etc).
** Dependencies look right, but my application is still failing to load – why?
There are three ways to further debug that scenario:
1) Open the Event Viewer and change the errors generated. The error will tell you which assembly failed to load.
2) Use depends.exe on the image that is failing to load. It should point out which dependency was not found.
3) On Vista, you can use sxstrace.exe to get a step-by-step log of how fusion tries to resolve your dependency and why it failed.
** For Beta Users
If you are using VS Beta releases, make sure you do not mix bits between them (a lib built with Beta1 linked with objs built with Beta2 for example).
** Why my Beta1 exe stopped working after installing Beta2 runtimes?
The reason for that is we do not change the assembly identity during a product cycle – so, both Beta1 and Beta2 have the same identity for CRT (for example). This means that fusion gets to load only one redirection policy for a given library – and that policy is whatever that is most recent on your machine. In the scenario of Beta1 and Beta2, the Beta1 policy will be always ignored and the Beta2 policy will be loaded. And since we do not include any information about redirecting Beta1 clients in the Beta2 policy, Beta1 clients will fail to load. We might consider adding Beta1 redirection to Beta2 in future product cycles if we get enough feedback that this is an important scenario. Note that Beta1 and Beta2 VC libs are not supposed to be side-by-side.
Let me if you have any questions and I’d be glad to answer them.