views:

1039

answers:

2

I am working on a Windows application (EXE) that uses multiple DLLs. Development is in VCExpress 2005 (VC 8.0), using C only.

Some of these DLLs are plug-ins/add-ons/extensions that are dynamically loaded using [LoadLibrary](http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx) according to a configuration file read by the EXE.

Importantly: the application must be portable (in the sense of able to run from a USB flash drive or similar without installation), and the plug-in DLLs may not be in the same folder as the application EXE (legacy reasons).

With MSVC6 this is straightforward: compile, link, distribute EXE and DLLs.

With MSVC8 the C Runtime Library (MSVCRT) is no longer distributed with the OS, so one cannot rely on it being installed. To satisfy the portability requirement I need to use a [private assembly](http://msdn.microsoft.com/en-us/library/aa375674(VS.85).aspx). All EXEs and DLLs have had their manifests embedded.

My problem: the plug-in DLLs loaded via LoadLibrary() do not find the private assembly that is in the EXE's folder, so attempting to load them fails unless the Microsoft.VC80.CRT assembly is installed in winSxS.

The catch: if the manifests are removed from the plug-in DLLs, everything works.

My questions:

  1. In the problem case, Windows doesn't seem to be following either the [Assembly searching sequence](http://msdn.microsoft.com/en-us/library/aa374224(VS.85).aspx) or the [Dynamic link library search order](http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx). Specifically it is looking for the private assembly in the path from which the DLL was loaded, not from which the application (EXE) was loaded. I have attempted to verify this by putting the assembly adjacent to the DLL, and changing the current directory (to rule out related to working directory cases), and get the expected behaviour. Can anyone else confirm that this is the normal behaviour when using LoadLibrary with SxS?

  2. Am I right in assuming that without a manifest, the DLL falls back to non-SxS load order which is finding msvcr80.dll (rather than the assembly manifest Microsoft.VC80.CRT.manifest) in the EXE's folder?

  3. If I am right about (1) and (2), what do I lose by just excluding the manifest from the DLL? Rephrased, why shouldn't I solve my problem by just excluding the manifest?

A: 

Link statically with the CRT. As long as you don't use .Net in your application (pure C/C++) it is possibly to statically link with the CRT.

The introduction of .Net in my application forced me to move from a statically linked CRT to a dynamically linked CRT. I also tried to find a way to refer to the CRT DLL's locally without the need to explicitly install them, but I didn't find it. Therefore, if possible, statically link with the CRT.

Patrick
Thanks - I see that http://stackoverflow.com/questions/238465 and http://stackoverflow.com/questions/787216 also discuss the relative merits of static vs dynamic linking. I am hesitant to use static linking as I'm not sure that the APIs don't permit/expect resource allocation and deallocation to happen in different modules, which will crash the app. Also static linking will lead to bloated binaries.
Twylite
+3  A: 

You need to understand what an activation context is to understand this problem.

An exe, or dll, with a manifest, has an activation context - the activation context is a list of window classes, dependent assemblies, dlls, and registration free com references that where discovered when the manifest was parsed.

An exe, or dll, without a manifest, uses the process default activation context - which is usually the exe's activation context if the exe has an activation context.

In your case, the dll has its own activation context - because it has a manifest. And, its always the path to the (file that contains the) manifest file that is searched for assemblies.

Which is why windows starts by searching the dll's folder for the private assembly. Then, when that fails, Windows searches the standard load library search path for the dll: which starts with the exe's root folder. but its searching for dll's now, NOT assemblies - so the assembly folder containing the dll is not found.

  1. No. Without a manifest, the dll falls back to using the default activation context: the exe's manifest. This Blog Article explains it a bit.

  2. Exclude the manifest. What you loose is the ability to get the dll to specify its own dependent assemblies. What you need to do therefore, is add any dependent assemblies the dll needs, to the applications manifest.

Chris Becke
One point to add - the loader appears to ignore the application local directory when an embedded manifest contains a publicKeyToken reference.
Eric W.
The loader *always* looks in WinSxS first if it has enough information. It will fall back to local however even if there is a publicKeyToken.
Chris Becke