DLL dependencies for portable C/C++ application for Windows - c++

I want to create a light-weight portable application in C/C++ for Windows. I don't want to statically link everything because I want to keep the size of exe as small as possible. I also use Dependency Walker to track the DLL dependencies of my exe file.
My question is that what are the list of DLL dependencies that an application can have and stay portable across different versions of Windows? With this list at hand I can check the output from Dependency Walker with the list and choose which libraries to link statically and which to link dynamically. I prefer the list contain OSes from Windows XP higher, but having Windows 98 in mind is also interesting.

Create a basic Win32 application in something like Visual Studio and check the dependencies with Dependency Walker. Those are your base dependencies. All of the standard Win32 DLL files will be required, including user32.dll, kernel32.dll, and so on. (Although some of this varies, depending on what you want the application to do. In some cases, you can get away with only kernel32.dll, but you won't be able to show a window on the screen. Probably a fairly useless app.)
Keep in mind that the last version of Visual Studio that can compile applications that run on Windows 98 is Visual Studio 2005. Visual Studio 2008 can target a minimum of Windows 2000, while VS 2010 can target a minimum of Windows XP SP2. You'll need to either use an older version of the compiler, or edit the executable file's PE header manually to change the subsystem field.
If you're really into things like this (although it's honestly a waste of time) you should investigate Matt Pietrek's LIBCTINY, originally from an article published in MSDN Magazine back in January of 2001. This little library makes it theoretically possible to use the /NODEFAULTLIB compiler flag in order to avoid linking to the CRT.

If you are linking to standard Windows DLLs then there's no issue because the DLLs are already present on the target systems.
For other DLLs, if you have to distribute the DLL then your total executable code size will be greater than if you had used static linking. You only end up with smaller executable code size if you have multiple applications that use common libraries.
In other words, although dynamic linking sounds seductive, old fashioned static linking may be better for you.
Now, if you are concerned about linking to a C runtime then you could consider using mingw which can link against the Windows C runtime which is present on all systems.

I'm assuming you're using VC. Microsoft provides the list you're looking for in MSDN. See:
Redistributing Visual C++ Files
Determining Which DLLs to Redistribute
Note that the list changes based on VC's version (you can choose yours on the top of the pages). Also, on modern versions of Windows, it is advised to properly install the runtime dlls using VCRedist_*.exe - it would probably make your programs less portable than you wish, but it's a one-time installation of (sort of) system components, that no-one will ever have to uninstall.

Related

CRT library type

I'm trying to get a better grasp on the CRT library options in Visual Studio 2013 (C++ -> Code Generation -> Runtime Libary) and how to know which option to select (and when to change the default).
From MSDN:
A reusable library and all of its users should use the same CRT library types and therefore the same compiler switch.
So, my understanding is that if you are linking with a third party library, you should use the same CRT version that was used to build the library. Whoever built the library should specify what CRT option was used in the build.
Is there a way to determine which CRT version was used just by looking at the .lib file?
More importantly, how would you decide which option to use if you aren't linking with any third-party libraries? When would you consider changing the default?
Short answer:
So, my understanding is that if you are linking with a third party
library, you should use the same CRT version that was used to build
the library. Whoever built the library should specify what CRT option
was used in the build.
That is the least error-prone option. It is possible to mix runtimes, but you can run into unexpected bugs if you do so.
Is there a way to determine which CRT version was used just by looking
at the .lib file?
I don't know about the .lib on its own, but if the third party code has a DLL or EXE, you can see what CRT DLL(s) it depends on using the Windows Dependency Walker tool.
If it's a static library, and your code's CRT choice is mismatched, you'll see warnings when you build.
More importantly, how would you decide which option to use if you
aren't linking with any third-party libraries? When would you consider
changing the default?
For the simplest possible deployment, statically linking is best; you can just ship the executable on its own and it will run. For larger projects, where you have multiple EXEs and DLLs, your code size will be bigger if you statically-link. It would also be preferable to be sharing the same CRT code if you have multiple modules (EXE plus 1 or more of your own DLLs) in the same process.
More detail (based on blog post I wrote previously):
The Library Variants
There are four variants of C/C++ runtime library you can build your code against:
Multi-threaded Debug DLL
Multi-threaded DLL
Multi-threaded Debug
Multi-threaded
You can select which library you’re using by right-clicking on your project in Visual Studio and selecting Properties, clicking the Code Generation option under C/C++ on the dialog that pops up, and going to the Runtime Library property.
Remember that this setting is per-configuration, as you’ll want to choose a Debug runtime library for a Debug configuration, and Release runtime library for a Release configuration.
What’s the difference?
The DLL runtime library options mean that you link dynamically against the C/C++ runtime, and for your program to run, that DLL will need to be somewhere your program can find it (more on that later).
The options not mentioning DLL (Multi-threaded Debug and Multi-threaded Release) cause your program to be statically-linked against the runtime. This means that you don’t need an external DLL for the program to be run, but your program will be bigger because of the extra code, and there are other reasons why you might not want to choose it.
By default, when you create a new project in Visual Studio, it will use the DLL runtime.
The multi-threaded in the runtime names is a legacy of when there used to be both non-thread-safe and multi-threaded C/C++ runtimes. You’ll always be using a multi-threaded runtime with modern Visual Studio, even if your own application is single-threaded.
Deploying DLL Runtimes
If you’re linking against the DLL runtimes, then you’ll have to think about how to deploy them when releasing your program (to Test, and to your customers).
If you deliver Debug builds to your Test team, make sure you provide the Debug variant of the DLL runtimes too.
Also, don’t forget to get the right architecture (e.g. x86 vs x64).
Redistributable Installers
Microsoft provide redistributable packages that install the Release (but not the Debug) DLLs. These can be found easily enough by searching for something like Visual C++ Redistributable 2013 (substituting the Visual Studio version for what you need). You can also go straight to Latest Supported Visual C++ Downloads on Microsoft’s website.
These redistributables packages are executables, and you can call them from your program’s installer (or you could run them manually for setting up a test environment). Note that there are separate redistributables for x86 and x64.
Merge Modules
If you’re building an MSI installer, you can merge the Merge Module for the C/C++ runtime you’re using into your installer package. These merge modules are typically found in C:\Program Files (x86)\Common Files\Merge Modules. For example, the x86 C/C++ runtime’s merge module for Visual Studio 2013 is called Microsoft_VC120_CRT_x86.msm.
Note that the version numbers in these merge module names are not the year-based product versions, but the internal version numbers. This table on Wikipedia shows the mapping between the version numbers for avoidance of confusion.
Unlike the stand-alone executable redistributable installers above, the merge modules also come in Debug variants.
Some versions of Visual Studio have support for a Visual Studio Installer project type (under the Setup and Deployment category in Other Project Types), and if you include the output from your program’s projects in one of these installers, the merge modules for the runtime will be included automatically. You can also use this as a trick to get an installer that will install the Debug runtimes for internal testing purposes (any dummy C/C++ project will do, it doesn’t have to actually install your program).
Copy From Redist Folder
You can also just copy the DLLs from the redist folder in your Visual C++ installation into where your program is installed. For example, for Visual Studio 2013, you’ll find the x64 C/C++ runtime libraries somewhere like C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x64\Microsoft.VC120.CRT\.
The debug variants can be found somewhere like C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\Debug_NonRedist.
(Adjust paths as appropriate for your Visual Studio version and installation location).
Mixing C/C++ Runtimes
In an ideal world, you would use the same C/C++ runtime library variant (Debug vs Release, DLL vs statically-linked), and all from the same version of Visual Studio, for all libraries being linked into your program.
If you do mix runtimes, you may get linker errors, your program may simply fail to run at all, or worse still, it may seem to be working but crash or give the wrong result only in some cases.
Ignoring Default Libraries
A common scenario is that you only have the Release version of some third-party library, but you still want to be able to build the Debug variant of your own code using this library. Another scenario is that you have a library that uses the static C/C++ runtime and you want the DLL version in your program, or the reverse.
If the third-party library is C code then you’ll probably be able to get away with this and have it actually work, using the /NODEFAULTLIB linker option.
If the library is C++ code, you are probably out of luck as too much of the generated code is tied to symbols in a particular runtime.
These are the different library names:
LIBCMT.LIB: Statically-linked Release runtime (a.k.a. Multi-threaded)
LIBCMTD.LIB: Statically-linked Debug runtime (a.k.a. Multi-threaded Debug)
MSVCRT.LIB: Dynamically-linked Release runtime (a.k.a. Multi-threaded DLL)
MSVCRTD.LIB: Dynamically-linked Debug runtime (a.k.a. Multi-threaded Debug DLL)
Remember, the runtime libraries you want to ignore are the ones that the third-party code is using, i.e. it will be different from the library that your own program is using. If you look at your build output you will be prompted to choose the right one anyway, e.g.:
LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library
You can specify the library to ignore by right-clicking on your project, selecting Properties, clicking the Input entry under Linker and adding the runtime library name into the entry.
Crossing Module Boundaries
You can also run into C/C++ runtime mismatch problems in more subtle ways across module boundaries (between an EXE and a DLL it loads for example).
For example, data structures in the C library may be defined differently by different runtimes. I’ve seen this cause crashes in programs that used a DLL that made use of a FILE* in its API. A file is opened in one module using one C runtime, and interacted with by another module which has a different, incompatible implementation. Safer options would include passing Windows API HANDLE objects for things like this, or else wrapping up the file interactions in a way that is runtime-agnostic.
Different runtimes also use their own memory heap for allocations. If an object is allocated in one module on one heap, but deallocated in another module, a crash is likely to occur if the C/C++ runtimes are mismatched. This only applies of course to allocations using the C or C++ runtime such as malloc or new. If the default Windows process heap is being used everywhere, for example, everything is fine.
Note that if the modules statically link against the C/C++ runtime, they will have this problem even if it was the same variant of the runtime they linked against, because there will still be two different runtimes with their own memory heaps in play. Therefore, you will want to use the DLL C/C++ runtime in such circumstances.
It would also be wise to use the (same version of) DLL runtimes in each module if runtime-implemented functionality like exceptions or classes with vtables cross the module boundaries, though some combinations of mismatch may work in practice.

Visual Studio 2010 MSVCR dependency removal?

I've tried Googleing this but I could not find a solution. I am trying to learn some basic C++. I wrote a simple hello world:
#include <stdio.h>
int main()
{
printf("hello, world\n");
return 0;
}
It compiled perfectly and everything! Great I thought, so I loaded up my virtual machine with XP and no service packs installed, then tried to run it. It told me I needed the MSVCR dll. Is there any way I can completely remove this dependency? I don't want to stuff the program with the dll. I want it to be gone, completely. Is it possible to make and run a program that will run in XP and up? Thanks.
It is technically possible to remove this dependency in C, but I'm not sure it is even possible in C++. And in either case, I would not recommend it. You lose a lot of stuff that the CRT does for you behind the scenes, most of which you don't want to have to reinvent yourself in an inferior fashion. For starters, it's the runtime library that actually calls your main function as well as calling the constructors and destructors for global and static C++ objects.
The best and simplest solution is probably to change how your application links to the runtime libraries. You have two different options: dynamically and statically. Dynamic linking is more memory-efficient and means that your application will take advantage of any bug fixes that are made to the library. It relies on the runtime DLL being present in order for your app to start. Static linking actually embeds the runtime library code into your application during the link phase of the build. This means that you can run without distributing the DLL, but there are important caveats.
For simple apps, it's unlikely that these caveats are relevant. Change the link style in use in your project's options:
Right-click on your project name in the Solution Explorer.
Expand the "C/C++" option in the left-hand treeview, and select the "Code Generation" item.
In the "Runtime Library" property combobox, choose one of the "Multi-threaded" options.
Debug builds should use "Multi-threaded Debug", while Release builds should use "Multi-threaded".
Do note that since you're using VS 2010, you can still choose to dynamically link to the runtime and gain all of the advantages of doing so without having to run the CRT installer on the target machines. All you need is the redistributable DLL(s) placed into the same folder as your application's executable. This makes deploying (and even testing) very simple and straightforward. You'll find these libraries as part of your Visual Studio installation:
\Program Files\Visual Studio x.0\VC\redist\
And of course, the debug versions of the CRT are never redistributable. Since you should not distribute debug versions of your application, this is not a problem. Make sure that you've compiled a "Release" build (using the drop-down combobox in the top toolbar), for which you will require only the redistributable libraries found in the above directory.
Can't I use the runtime that comes with XP?
There is no C runtime for you to use that comes with any version of Windows. Windows itself indeed depends on a C runtime library, but it deploys a private version of that library for its own use. Applications are not intended to link to it or make use of it in any way. You're on your own for deploying all necessary dependencies, and as you've noticed, you cannot assume that the target machines will already have the correct version(s) installed.
You can link the MS runtime statically, Project Options -> C/C++ -> Code Generation -> Multithreaded (or Multithreaded Debug for debugging configuration). No DLL should be needed then.
you can remove the annoying run-time library, do this:
project properties > linker > input > ignore all default libraries> yes
this will give you quiet a few issues you need to deal with, for example, floating
point numbers won't work, stack memory is very small (about 3k), there's no built in help against buffer overflows and such, and you can't use the standard library without copy pasting it in your project.
this will also decrease the size of the .exe nearly equivalent to as if it was hand made
in assembly.

Standalone VS 2010 C++ Program

it's been a long while since I've used VS 2010 and C++, and as I'm getting back to using it, I'm running into the same problems that plagued me last year: the exe's that I compile do not run well on older machines that do not have the correct C++ runtimes. I do not even know what link to give them, and I told them to install this after they had an error that said "The program can't start because MSVCR100.dll is missing from your computer. Try Reinstalling the program to fix this problem. Click OK to close the application."). So I went in and set the code generation to /MT and disabled quite a few options, and tried messing around with lots of options, but still the same result.
My question is: Is there a list of complete VS 2010 C++ distributables that I can just give and tell them to install so all of the C++ programs I compile on my VS 2010 will work on Windows XP, or even better, a way to general a standalone exe that contains all it needs to work, and does not rely on DLLs? I'm thinking like linking to a library that has everything the exe references. If it helps, I'm building for both x64 and x86.
P.S. What's up with the manifest file, should I include it or not?
The easiest thing to do is to just install the VC++ Redistributable Package. It has both x86 and x64 versions.
Firstly, before I actually give you the detail:
Warning
If you do this, things will be bad for two reasons:
If there are security or other bugs in the MSVC runtimes, and you take this approach, they're baked into your app which means you need to re-distribute. DLLs are preferred because theoretically people use system update which means any errors get fixed.
Everything else you compile into your exe also needs to do this. If you don't, you end up with two versions of the code and whatever you're using won't link.
One possible solution is to bake the MSVC runtime into your application, by using the cl.exe option (C/C++ compiler settings) /MT which means multi-threaded version of the C/C++ runtime linked statically. As I said, if you try to link against something that is linked itself dynamically to the runtime, you're going to end up in a mess. Also, as I said, this represents an additional security risk factor, so bear that in mind.
The other options are to write an installer that can either download the appropriate runtime, or include the DLL needed.
If you're using some feature of the runtime that exceeds a certain version of Windows (generic statement, but it does happen) then you should be able to use the Windows SDK to target various versions of Windows using appropriate C runtimes.
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=a7b7a05e-6de6-4d3a-a423-37bf0912db84
google text: visual studio c++ redist
Do not statically link to the runtime; specifically don't do so if you're using any kind of dll for other purposes. It introduces all kinds of bogus problems wrt heap management that you probably don't want to mess with.
Open the properties dialog for your project and select Configuration Properties | C/C++ | Code Generation. The default setting is Multi-threaded DLL. Change that to Multi-threaded and you'll be building and .EXE with the run-time statically linked in. Don't forget to do the same for the debug version.
If you're using MFC or ATL, you will need to navigate to Configuration Properties | General and set "Use of MFC" or "Use of ATL" to link statically as well.
NB: If you link the runtime statically, you must make sure that any other library you're linking in also links it in statically. Otherwise you'll wind up with two copies of the runtime in memory, each with its own heap and bad things will happen when code using one runtime tries to free an object allocated by the other runtime.
This previous answer should hold true for VS2010. I still build with VS2005, but all my apps use the static CRT for the sole reason of being able to run across old and newer machines alike.

Alternatives to including MS C runtime distro?

I use MSVS 2010 and MSVC++E 2010 to build my applications in C++ and I've notice a lot of my friends (who test my apps on their PCs) don't have the Microsoft C++ runtime library installed on their computers. I've started including the Microsoft C++ redistributable package with my apps, but this seems unnecessary. Would I be able to instead include the libraries in my executable directory? I know that one of the libraries used is msvcr100.dll, but are there also others I need to include? Or is the redistro my best option?
in your project options, for code generation, you can choose the STATICally linked libraries instead of the DLL versions. That eliminates the need for an external dependency like this, at the cost of a larger EXE.
You don't necessarily need to HAVE to have the runtime library within your executable directory, you may use a Manifest File that has a relative path which points to runtime if you wish. But yes, you can include the libraries within the install of your application.
I think we lug around the msvcr as well as the msvcrt and the msvcp DLLs which now that I'm writing that out, might be a bit overkill.
When you build your application to a static runtime, you don't need to distribute the runtime dlls.
Otherwise you have to include the Microsoft runtime.
Links to runtime installers for Visual Studio 2010
Compiling your project with /MT solves the distribution problem. Be careful though, it can get you in trouble when you use DLLs. They will have their own memory allocator. If they export a function that exposes a pointer or a C++ object that needs to be released by the client code then you'll have a very hard to diagnose memory leak on your hands. Very easy to do, just return an std::string for example.
Anyhoo, the setting is found by right-clicking the project in the Solution Explorer window, Properties, C/C++, Code generation, Runtime Library setting.
Also note that VS2010 supports local deployment. Just put the msvcr100.dll file in the same directory as your EXE. You also need msvcp100.dll if you use STL or iostreams.

Working with Visual Studios C++ manifest files

I have written some code that makes use of an open source library to do some of the heavy lifting. This work was done in linux, with unit tests and cmake to help with porting it to windows. There is a requirement to have it run on both platforms.
I like Linux and I like cmake and I like that I can get visual studios files automatically generated. As it is now, on windows everything will compile and it will link and it will generate the test executables.
However, to get to this point I had to fight with windows for several days, learning all about manifest files and redistributable packages.
As far as my understanding goes:
With VS 2005, Microsoft created Side By Side dlls. The motivation for this is that before, multiple applications would install different versions of the same dll, causing previously installed and working applications to crash (ie "Dll Hell"). Side by Side dlls fix this, as there is now a "manifest file" appended to each executable/dll that specifies which version should be executed.
This is all well and good. Applications should no longer crash mysteriously. However...
Microsoft seems to release a new set of system dlls with every release of Visual Studios. Also, as I mentioned earlier, I am a developer trying to link to a third party library. Often, these things come distributed as a "precompiled dll". Now, what happens when a precompiled dll compiled with one version of visual studios is linked to an application using another version of visual studios?
From what I have read on the internet, bad stuff happens. Luckily, I never got that far - I kept running into the "MSVCR80.dll not found" problem when running the executable and thus began my foray into this whole manifest issue.
I finally came to the conclusion that the only way to get this to work (besides statically linking everything) is that all third party libraries must be compiled using the same version of Visual Studios - ie don't use precompiled dlls - download the source, build a new dll and use that instead.
Is this in fact true? Did I miss something?
Furthermore, if this seems to be the case, then I can't help but think that Microsoft did this on purpose for nefarious reasons.
Not only does it break all precompiled binaries making it unnecessarily difficult to use precompiled binaries, if you happen to work for a software company that makes use of third party proprietary libraries, then whenever they upgrade to the latest version of visual studios - your company must now do the same thing or the code will no longer run.
As an aside, how does linux avoid this? Although I said I preferred developing on it and I understand the mechanics of linking, I haven't maintained any application long enough to run into this sort of low level shared libraries versioning problem.
Finally, to sum up: Is it possible to use precompiled binaries with this new manifest scheme? If it is, what was my mistake? If it isn't, does Microsoft honestly think this makes application development easier?
Update - A more concise question: How does Linux avoid the use of Manifest files?
All components in your application must share the same runtime. When this is not the case, you run into strange problems like asserting on delete statements.
This is the same on all platforms. It is not something Microsoft invented.
You may get around this 'only one runtime' problem by being aware where the runtimes may bite back.
This is mostly in cases where you allocate memory in one module, and free it in another.
a.dll
dllexport void* createBla() { return malloc( 100 ); }
b.dll
void consumeBla() { void* p = createBla(); free( p ); }
When a.dll and b.dll are linked to different rumtimes, this crashes, because the runtime functions implement their own heap.
You can easily avoid this problem by providing a destroyBla function which must be called to free the memory.
There are several points where you may run into problems with the runtime, but most can be avoided by wrapping these constructs.
For reference :
don't allocate/free memory/objects across module boundaries
don't use complex objects in your dll interface. (e.g. std::string, ...)
don't use elaborate C++ mechanisms across dll boundaries. (typeinfo, C++ exceptions, ...)
...
But this is not a problem with manifests.
A manifest contains the version info of the runtime used by the module and gets embedded into the binary (exe/dll) by the linker. When an application is loaded and its dependencies are to be resolved, the loader looks at the manifest information embedded in the exe file and uses the according version of the runtime dlls from the WinSxS folder. You cannot just copy the runtime or other modules to the WinSxS folder. You have to install the runtime offered by Microsoft. There are MSI packages supplied by Microsoft which can be executed when you install your software on a test/end-user machine.
So install your runtime before using your application, and you won't get a 'missing dependency' error.
(Updated to the "How does Linux avoid the use of Manifest files" question)
What is a manifest file?
Manifest files were introduced to place disambiguation information next to an existing executable/dynamic link library or directly embedded into this file.
This is done by specifying the specific version of dlls which are to be loaded when starting the app/loading dependencies.
(There are several other things you can do with manifest files, e.g. some meta-data may be put here)
Why is this done?
The version is not part of the dll name due to historic reasons. So "comctl32.dll" is named this way in all versions of it. (So the comctl32 under Win2k is different from the one in XP or Vista). To specify which version you really want (and have tested against), you place the version information in the "appname.exe.manifest" file (or embed this file/information).
Why was it done this way?
Many programs installed their dlls into the system32 directory on the systemrootdir. This was done to allow bugfixes to shared libraries to be deployed easily for all dependent applications. And in the days of limited memory, shared libraries reduced the memory footprint when several applications used the same libraries.
This concept was abused by many programmers, when they installed all their dlls into this directory; sometimes overwriting newer versions of shared libraries with older ones. Sometimes libraries changed silently in their behaviour, so that dependent applications crashed.
This lead to the approach of "Distribute all dlls in the application directory".
Why was this bad?
When bugs appeared, all dlls scattered in several directories had to be updated. (gdiplus.dll) In other cases this was not even possible (windows components)
The manifest approach
This approach solves all problems above. You can install the dlls in a central place, where the programmer may not interfere. Here the dlls can be updated (by updating the dll in the WinSxS folder) and the loader loads the 'right' dll. (version matching is done by the dll-loader).
Why doesn't Linux have this mechanic?
I have several guesses. (This is really just guessing ...)
Most things are open-source, so recompiling for a bugfix is a non-issue for the target audience
Because there is only one 'runtime' (the gcc runtime), the problem with runtime sharing/library boundaries does not occur so often
Many components use C at the interface level, where these problems just don't occur if done right
The version of libraries are in most cases embedded in the name of its file.
Most applications are statically bound to their libraries, so no dll-hell may occur.
The GCC runtime was kept very ABI stable so that these problems could not occur.
If a third party DLL will allocate memory and you need to free it, you need the same run-time libraries. If the DLL has allocate and deallocate functions, it can be ok.
It the third party DLL uses std containers, such as vector, etc. you could have issues as the layout of the objects may be completely different.
It is possible to get things to work, but there are some limitations. I've run into both of the problems I've listed above.
If a third party DLL allocates memory that you need to free, then the DLL has broken one of the major rules of shipping precompiled DLL's. Exactly for this reason.
If a DLL ships in binary form only, then it should also ship all of the redistributable components that it is linked against and its entry points should isolate the caller from any potential runtime library version issues, such as different allocators. If they follow those rules then you shouldn't suffer. If they don't then you are either going to have pain and suffering or you need to complain to the third party authors.
I finally came to the conclusion that the only way to get this to work (besides statically linking everything) is that all third party libraries must be compiled using the same version of Visual Studios - ie don't use precompiled dlls - download the source, build a new dll and use that instead.
Alternatively (and the solution we have to use where I work) is that if the third-party libraries that you need to use all are built (or available as built) with the same compiler version, you can "just" use that version. It can be a drag to "have to" use VC6, for example, but if there's a library you must use and its source is not available and that's how it comes, your options are sadly limited otherwise.
...as I understand it. :)
(My line of work is not in Windows although we do battle with DLLs on Windows from a user perspective from time to time, however we do have to use specific versions of compilers and get versions of 3rd-party software that are all built with the same compiler. Thankfully all of the vendors tend to stay fairly up-to-date, since they've been doing this sort of support for many years.)