Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
166 views
in Technique[技术] by (71.8m points)

c++ - A way to load DLL from central repository

We have lot of products and there are some common DLLs across each product's application. Right now we copy each common DLL into each product's bin directory and treat them as private assembly. This unnecessarily increase the msi size of each product and when a problem occurs in a DLL we have to build each product's msi comprising the DLL and deploy it.

Is there anyway to instruct the product application to use a common private directory to be used for loading DLLs [ using manifest scheme.. ]? [ Note: Adding the private directory to PATH env will not provide a solution as if there is a DLL with same name exist in SYSTEM directory, that would take the privilege over our private directory ]

-Kartlee

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You don't specify if your environment is .NET or straight Win32.

I am assuming its Win32 because if its .NET the technologies to do this are all much closer to hand in terms of things like the Global Assembly Cache.

In terms of Win32 it is possible to load Dlls from a shared location in one of two ways:

  • Use LoadLibrary with explicit full paths. This means you cannot use static linking - all dll functions used in all products will have to be accessed via GetProcAddress. You cannot import c++ classes from dll's loaded via LoadLibrary - they must be statically linked to work so this approach may or may not be viable. Its not terribly hard to write shim header files that masquerade as the dll's interface and do a just in time dll load and GetProcAddress as needed for each call.

  • The other option is to turn the dll's into what are called "side by side assemblies" and install them into the WinSxS store. Don't be scared by the big name. "side by side assembly" means "A Dll file plus manifest file with version information". Each of the various applications would then put 'strong name' - which includes version information - into its application manifest for each dll it uses, and the Win32 Dll loader will use this to pick the correct instance of the common dll from the WinSxS store. The basic process is described in the MSDN article Guidelines for Creating Side-by-side Assemblies


On Windows versions 6.1 and up (Windows Server 2008 and the ironically named Windows 7) application configuration files DO NOW support the probing element in Application Configuration Files

This means you should be able to provide a path (relative to your application) to a folder containing containing dll assemblies you want to load.


I've done some testing on Windows 7, and this works:

Assuming you have an application app1.exe installed in Program FilesApp1 that depends on some common dll "thedll.dll"

In the application folder (Program FilesApp1) create a file App1.exe.config and give it the following contents :

<configuration>   
   <windows>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <probing privatePath="..AcmeCommon"/>
    </assemblyBinding>
  </windows>
</configuration>

Now, create a folder called Program FilesAcmeCommon, and in it a folder acme.thedll, and copy thedll.dll into Program FilesAcmeCommonacme.thedll

Also create a file in AcmeCommonacme.thedll called acme.thedll.manifest - this will be the assembly manifest describing the assembly called 'acme.thedll'

The contents of acme.thedll.manifest will be:-

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity name="acme.thedll" version="1.2.3.4" processorArchitecture="x86"  type="win32"/>
    <file name="thedll.dll"/>
</assembly>

Now we have the common dll, in a common location, as a native sxs assembly. We have the app, with a config file that will, on Windows 7 and 2008 server (and up) tell it to search for assemblies in the common location. But the app is still trying to link to the dll as a dll, rather than via an assembly.

To get the app to load the assembly, we need to add a manifest file to the application. If you are using visual studio, your applications are probably already configured to create and embed manifests via the linker and manifest tool project settings. In which case the easiest way to tell the app about the assembly is to rebuild it after adding the following code to at least one header or c/cpp file in the project :-

#pragma comment(linker,"/manifestdependency:"type='win32' name='acme.thedll' version='1.2.3.4' processorArchitecture='x86' language='*'"")

If you are using an older build environment where the manifests are hand made you would need to merge the following xml with app1.exe.manifest in the App1 folder:

<dependency>
  <dependentassembly>
    <assemblyIdentity type="win32" name="acme.thedll" version="1.2.3.4"   processorArchitecture="x86" language="*"/>
  </dependentassembly>
</dependency>

This should close the circle: When the app loads the win32 loader will load the application manifest (app1.exe.manifest or embedded as a RT_MANIFEST resource) and learn about the "acme.thedll" assembly. It will also load the application config file (app1.exe.config) and learn about the private path to search for assemblies. And it will then load and add "acme.thedll.manifest" to the apps "activation context". Then, when the loader tries to load "thedll.dll" it will search the activation context db, find that it's in the acme.thedll assembly, and load it from the assemblies location.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...