Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LoadLibrary() fails to load DLL with manifest and private assembly

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 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. 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 or the Dynamic link library search order. 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?

like image 633
Twylite Avatar asked Feb 25 '10 16:02

Twylite


1 Answers

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 were 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/folder 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.

like image 181
Chris Becke Avatar answered Nov 13 '22 11:11

Chris Becke