DLL Hell
The phenomenon of inconsistent mixes of DLLs leads to a condition known affectionately
as "DLL Hell". Even Microsoft calls it this. The problem is that if
Microsoft DLL A requires Microsoft DLL B, it is essential that it have the correct
version of DLL B. Of course, all of this stems from a desire to not rename the
DLLs on every release with a name that includes the rev level and version number
or other useful indicators, but the result is that life becomes quite unbearable.
Microsoft has a Web site that allows you to determine if you have a consistent
mix of DLLs. Check out http://msdn.microsoft.com/library/techart/dlldanger1.htm
for articles about this. One of the nice features is that much of this is going
away in Win2K and WinXP. However, some of it is still with us. Sometimes the
release version of your code will be done in by a mismatch whereas the debug
version is more resilient, for all the reasons already given.
However, there is one other lurking problem: a mix of DLLs that use the shared
MFC library, and are both debug and release. If you are using DLLs of your own,
that use the shared MFC library, make certain that all your DLLs are either
debug or release! This means you should never, ever, under any circumstances
rely on PATH or the implicit search path to locate DLLs (I find the whole idea
of search paths to be a ill-thought-out kludge which is guaranteed to induce
this sort of behavior; I never rely on the DLL load path except to load
the standard Microsoft DLLs from %SYSTEM32%, and if you are using any kind of
search path beyond that you deserve whatever happens to you! Note also that you
must not, ever, under any circumstances imaginable, ever, put a DLL of your own
in the %SYSTEM32% directory. For one thing, Win2K and WinXP will delete it anyway,
because of "System32 Lockdown", a good idea that should have been forcefully
implemented a decade ago).
Do not think that doing "static linking" of the MFC library is going
to solve this problem! In fact, it actually makes the problem much worse, because
you can end up with n disjoint copies of the MFC runtime, each one of
which thinks it owns the world. A DLL must therefore either use the shared MFC
library or use no MFC at all (the number of problems that occur if you have a
private copy of the MFC library are too horrible to mention in an otherwise G-rated
Web page, and in the interest of preserving keyboards I won't describe them in
case any of you are eating when you read this. Well, how about one: the MFC Window
Handle Map. Do you really want two or more copies of a handle map, each
one of which can have disjoint images of what the window handle mapping, and
try to reconcile the behavior of your program? I thought not).
However, it is very important to not have a mix of debug and release DLLs using
MFC (note that a "straight", non-MFC release DLL can be called from
a debug version of an MFC program; this happens all the time with the standard
Microsoft libraries for OLE, WinSock, multimedia, etc.). The debug and release
DLLs also have sufficiently different interfaces to MFC (I've not looked in detail,
but I've had reports about problems) that you will get LoadLibrary failures,
access faults, etc.
Not A Pretty Sight.
One way to avoid this is to have your DLL subprojects compile the DLLs into
the main program's Debug and Release directories. The way I do this is to go
into the DLL subproject, select Project Settings, select the Link tab, and put
"..\" in front of the path that is there. You have to do this
independently in the Debug and Release configurations (and any custom configurations
you may have).
I also hand-edit the command line to put the "..\" in front
of the path for the .lib file, making it easier to link as well.
Note the yellow areas highlighted in the image below. The top left shows the
fact that I am working in the Debug configuration. The middle right shows
the edit I made to the output file, and the lower right shows the hand-edit I
made to redirect the .lib file.