Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I organise third-party Windows DLLs into a subfolder in my application folder?

Tags:

windows

dll

We have an application that depends on a number of groups of third-party DLLs. Unfortunately, none of the writers of these third-party DLLs have named them very consistently so it is hard to see which DLL is part of what group.

To try and manage this, we would like to put groups of third-party DLLs in a folder in our application folder rather than along-side the application something like this.

--> Application Folder
    --> Application.exe
    --> MyDLL1.dll
    --> MyDLL2.dll
    --> Third Party 1 DLL folder
        --> Third Party 1 DLL 1.dll
        --> Third Party 1 DLL 2.dll
        --> Third Party 1 DLL 3.dll
    --> Third Party 2 DLL folder
        --> Third Party 2 DLL 1.dll
        --> Third Party 2 DLL 2.dll
        --> Third Party 2 DLL 3.dll

My question is how to get the dynamic linker to find them and load them?

We could do this manually with LoadLibrary() and GetProcAddress(), however this is intensely tedious. It looks like we might be able to do this with manifests and "probing", but this seems to be Windows 7 only (we need to work on XP and above).

Update

We used manifests to do this in the end (thanks @Chris) - there were a couple of other hoops we had to jump through in case anyone is looking for a solution!

First, our "assembly" actually has several DLLs, one that we link to that then links to others. All of these DLLs will need the assembly dependency adding to their manifests (you can use mt.exe to do this without having access to the the source code of these DLLs).

Second, the assembly needs to go alongside the DLL, not alongside the EXE - our DLL was actually a plugin that was already in a subfolder of the app.

Here is our final layout:

--> Application Folder
    --> Application.exe
    --> Plugins folder
        --> MyDLL1.dll
        --> Third Party 1
            --> Third Party 1.manifest
            --> A.dll
            --> B.dll
            --> C.dll

If MyDLL1.dll is a plugin that links to A.dll, and A.dll links to both B.dll and C.dll then:

  1. "Third Party 1.manifest" needs to include all A.dll, B.dll and C.dll as an assembly
  2. "MyDLL1.dll" needs a dependency entry in its manifest to "Third Party 1" or the dynamic linker won't find A.dll
  3. A.dll needs a dependency entry in its manifest to "Third Party 1" or the dynamic linker won't find B.dll and C.dll
  4. The "Third Party 1" folder needs to go alongside "MyDLL1.dll", not alongside "Application.exe"

For me, (3) is a bit irritating. You would think that the linker would look in the assembly for dependent DLLs.

like image 448
Bids Avatar asked Oct 29 '10 10:10

Bids


2 Answers

You can do it with manifests without probing. Create "fake" assemblies - by defining .manifests, that contain the dlls. (No change is requried in the dll's for this) Since assembly support was added to NT 5.1 (Windows XP) the windows loader first looks for assemblies by scanning for a folder with the assemblies name.

So, for example, if you need to distribute the Microsoft Visual C runtime for Visual C 2008 with your application, you could create a folder structure that looks like this:

--> Application Folder
  --> Application.exe
  --> MyDll1.dll
  --> MyDll2.dll
  --> Microsoft.VC90.CRT
    --> Microsoft.VC90.CRT.manifest
    --> msvcr90.dll
    --> msvcp90.dll
    --> msvcm90.dll

This same scheme would work for your 3rd party dlls. All you would then need to do would be to add the "fake" assemblies as dependent assemblies to your application's manifest (if your dlls have manifests, (and they access the 3rd party dlls) then their manifests will have to have entries too.

The manifest files describing the assemblies need an assemblyIdentity, and a file node per dll:

<assembly manifestVersion="1.0">
  <assemblyIdentity type="Win32" name="Assembly Name" version="1.0.0.0" processorArchitecture="x86" />
  <file name="dll1.dll" />
  <file name="dll2.dll" />
</assembly>

And your application, and dlls are built with MS Visual Studio 2005 or later, the following pragma directive would make your app look for the dlls in the assemblies:

 #pragma comment(linker, "/manifestDependency:\"name='Assembly Name' processorArchitecture='*' version='1.0.0.0' type='win32' \"")
like image 176
Chris Becke Avatar answered Oct 09 '22 11:10

Chris Becke


You can use SetDLLDirectory function to specify path(s) for your DLLs. Alternatively read information about using application-specific paths.

like image 25
Eugene Mayevski 'Callback Avatar answered Oct 09 '22 13:10

Eugene Mayevski 'Callback