none
Cannot load 2 DLLs with same name, but different versions.

    Question

  •  

    Hi all,

     

    I have some problem during DLL loading.

     

    My application (C++) depends on some 3rd party DLL which is loaded during process start, let's call it a.dll (version 1).

    In my application lifetime, it dynamically  loads another 3rd party DLL (let's say b.dll) from its own directory. This b.dll depends on a.dll (version 2) which is also placed in same directory like b.dll.

     

    a.dll (version 2) is a little bit different from a.dll (version 1), API added, etc.

     

    During b.dll loading by call LoadLibrary fails with error 127. The reason is b.dll tried to use a.dll (version 1).

     

    I tried to use SetDllDirectory with LoadLibraryEx (with flag LOAD_WITH_ALTERED_SEARCH_PATH), but without success.

     

    In 3rd paragraph of http://msdn.microsoft.com/en-us/library/ms682586(v=VS.85).aspx  was mentioned that there is not possibility to do this. Is it true?

     

    Is there no possibility to solve this problem?

     

    Thanks,

    Oleg.

     

     

    Monday, November 29, 2010 8:37 PM

Answers

  • Ever since Windows XP, the system has used activation contexts to control where it looks for dlls. Each module (exe/dll) in a process can have an activation context - which is defined in a manifest file, or embedded resource in the module. If the file lacks a manifest, then it uses the default activation context that is associated with the exe.

    Dll's have to be part of an side-by-side (sxs) assembly to be searched for using this logic. Again, sxs assemblies are created by defining a manifest file that lists the dlls that are part of the assembly. So, we have three problems at this time:

    1. a.dll is not part of an assembly. This is relatively easy to fix. All you need to do is make up a name for the 'a' assembly, and create a .manifest file with that name. It should not have the same name as the dll as that can confuse things. The convention is to name it company.product.module. In this example, the file would be called "Acme.DllA.manifest"

        <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

        <assemblyIdentity name="Acme.DllA" processorArchitecture="x86" version="1.0.0.0" type="win32" />

        <file name = "a.dll"/>

        </assembly>

    There, now "a.dll" and "Acme.DllA.manifest" form an assembly. That part was easy. You don't even need the source to a.dll to do this.

    2. Your 'app.exe' does not load 'a.dll' using an activation context. This is also easy to fix. Add to a .cpp (or .h) file the following directive:

        #pragma comment(linker, "/manifestDependency:\"name='Acme.DllA' processorArchitecture='*' version='1.0.0.0' type='win32' \"")

    and rebuild and run.

    If it loads, then the system is using the activation context to find a.dll. Verify this by putting a typo in the #pragma and trying again to get really fun error messages. For extra points, create a folder called "Acme.DllA" in your exe folder, and move the .manfest and a.dll file into it - your program should still load as the system searches for assemblies both in the current folder, and subfolders with the name of the assembly.

    3. Your final problem is: b.dll is NOT searching an activation context for a.dll - b.dll either has no .manifest at all, or has a manifest, but it merely lists the c-runtime dll's. If you can rebuild b.dll, add the above pragma directive and you should be good to go. If you can't then you have two options that I can think of:

    a. Turn your app into a dll. Make a new exe file that simply calls an entry point in the app.dll, but the exe does NOT specify a dependency on the Acme.DllA assembly- your dll of course, does. Because your app.dll would be using a non default activation context to load 'a.dll', when b.dll tries to load a, it should fail to find it and then search for it normally.

    b. use the MT command line tool to merge a manifest dependency into B.Dlls manifest.

    Tuesday, November 30, 2010 10:39 AM
  • The manifest files are not needed during the build phases.

    With 1-2-3a - You need a folder structure that looks somewhat like this:

     

    +AppFolder

    --->app.exe

    --->app.dll       (with embedded dependentAssembly->Acme.DllA)

    +-->Acme.DllA

    ------>Acme.DllA.manifest

    ------>a.dll         (the version needed by app.dll)

    +-->Plugins

    ------>B.dll

    ------>A.dll          (the version needed by b.dll)        

    Wednesday, December 01, 2010 11:35 AM

All replies

  • Can't be done. Even if you have different module names, you are going to have trouble. The loader won't know how to resolve multiple entry points that have the exact same name. It's ambiguous.
    Monday, November 29, 2010 9:11 PM
  • Thanks for quick response.

     

    So what are my options?

    I found some information about manifest files that may deal with different dlls. Is it may help?

     

    If not, what may be proposed solution\workaround. For example, small executable which will load b.dll and will communicate with main program.

    Any other suggestions are welcome :).

     

    Thanks,

    Oleg.

    Tuesday, November 30, 2010 9:45 AM
  • Can you not modify your application to use a.dll (version 2) as well so that there is no conflict?
    Tuesday, November 30, 2010 10:07 AM
  • I can update in my application a.dll to version 2. But I'm looking general solution.

    Tomorrow, b.dll may use a.dll version 3 and I'll have same situation. 

    Tuesday, November 30, 2010 10:11 AM
  • Well, keeping your app updated to the latest version is the best general solution. The only other possibl solution is to load b into a seperate process and use IPC to communicate between the two. This would work because they are seperate processes so seperate address spaces.
    Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.
    Visit my (not very good) blog at
    http://c2kblog.blogspot.com/
    Tuesday, November 30, 2010 10:33 AM
  • Ever since Windows XP, the system has used activation contexts to control where it looks for dlls. Each module (exe/dll) in a process can have an activation context - which is defined in a manifest file, or embedded resource in the module. If the file lacks a manifest, then it uses the default activation context that is associated with the exe.

    Dll's have to be part of an side-by-side (sxs) assembly to be searched for using this logic. Again, sxs assemblies are created by defining a manifest file that lists the dlls that are part of the assembly. So, we have three problems at this time:

    1. a.dll is not part of an assembly. This is relatively easy to fix. All you need to do is make up a name for the 'a' assembly, and create a .manifest file with that name. It should not have the same name as the dll as that can confuse things. The convention is to name it company.product.module. In this example, the file would be called "Acme.DllA.manifest"

        <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

        <assemblyIdentity name="Acme.DllA" processorArchitecture="x86" version="1.0.0.0" type="win32" />

        <file name = "a.dll"/>

        </assembly>

    There, now "a.dll" and "Acme.DllA.manifest" form an assembly. That part was easy. You don't even need the source to a.dll to do this.

    2. Your 'app.exe' does not load 'a.dll' using an activation context. This is also easy to fix. Add to a .cpp (or .h) file the following directive:

        #pragma comment(linker, "/manifestDependency:\"name='Acme.DllA' processorArchitecture='*' version='1.0.0.0' type='win32' \"")

    and rebuild and run.

    If it loads, then the system is using the activation context to find a.dll. Verify this by putting a typo in the #pragma and trying again to get really fun error messages. For extra points, create a folder called "Acme.DllA" in your exe folder, and move the .manfest and a.dll file into it - your program should still load as the system searches for assemblies both in the current folder, and subfolders with the name of the assembly.

    3. Your final problem is: b.dll is NOT searching an activation context for a.dll - b.dll either has no .manifest at all, or has a manifest, but it merely lists the c-runtime dll's. If you can rebuild b.dll, add the above pragma directive and you should be good to go. If you can't then you have two options that I can think of:

    a. Turn your app into a dll. Make a new exe file that simply calls an entry point in the app.dll, but the exe does NOT specify a dependency on the Acme.DllA assembly- your dll of course, does. Because your app.dll would be using a non default activation context to load 'a.dll', when b.dll tries to load a, it should fail to find it and then search for it normally.

    b. use the MT command line tool to merge a manifest dependency into B.Dlls manifest.

    Tuesday, November 30, 2010 10:39 AM
  • wth happened to my formatting?

     

    Tuesday, November 30, 2010 10:39 AM
  • Thanks for your propose.

     

    So if I will use activation context, it will resolve the issue and my application will able to load same dll with 2 different versions, am I right?

    It looks like that 1-2-3.a is most acceptable solution.

    In addition, how it may influence on compilation/linkage where during compilation and runtime paths to dll are different? Should I create 2 different manifest files.

     

    Wednesday, December 01, 2010 11:01 AM
  • The manifest files are not needed during the build phases.

    With 1-2-3a - You need a folder structure that looks somewhat like this:

     

    +AppFolder

    --->app.exe

    --->app.dll       (with embedded dependentAssembly->Acme.DllA)

    +-->Acme.DllA

    ------>Acme.DllA.manifest

    ------>a.dll         (the version needed by app.dll)

    +-->Plugins

    ------>B.dll

    ------>A.dll          (the version needed by b.dll)        

    Wednesday, December 01, 2010 11:35 AM
  • Thanks a lot,

     

    I'll try it.

    Wednesday, December 01, 2010 2:40 PM