tags:

views:

519

answers:

5

Hi,

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

+1  A: 

If you're talking about .NET, you can:

  • Load your DLL directly from a database by using Assembly.Load(byte[])
  • By using Assembly.TypeResolve event
  • By using TypeProvider class
  • By defining a probe directory in your config file

Like:

<configuration>   
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <probing privatePath="bin"/>
        </assemblyBinding>
    </runtime>
</configuration>
Rubens Farias
Thanks for your reply. Unfortunately I am looking for C/C++ application which doesn't use any run time dynamic linking method ( like Loadlibrary(..) ) for example. Is there anyway to instruct through manifest like how 'probing' concept works?
Kartlee
@Kartlee, sorry I don't know about C/C++; but I edited your question to reflect that keywords
Rubens Farias
A: 

Hello,

I'm not sure if this is what you're looking for but where I work now we use a common UNC path for all of our DLL's.

We have something akin to ...

\\server01\productionLibrary for production read DLLs, each in it's own directory.

and

\\server01\developmentLibrary which mirrors the production library and this is what the developers use as they develop.

When we merge code after testing has been completed we deploy to the production library. All projects reference the production library when they are built into MSI files for deployment. Our automated system builds the projects into MSIs and it verifies that all DLLs are pointing to the production library, so there is no chance that it will use a development copy accidentally.

Hope this helps.

Scott Vercuski
A: 

I'm not sure I understand the question correctly, but if you're in .Net, there's a Global Assembly Cache (GAC): http://en.wikipedia.org/wiki/Global%5FAssembly%5FCache

This caches the assemblies and permits the reuse of them by applications (like with .net framework). You simply will need to register the assembly to GAC on the installation, for example provide a "your framework install" with all common assemblies, and this can be deployed only once.

Kel
Thanks for your reply. Please see my comment to 'Rubens Farias'.
Kartlee
A: 

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.


Ok, Ive done some testing on Windows 7, and this works:

Assuming you have an application app1.exe installed in \Program Files\App1, that depends on some common dll "thedll.dll"

In the application folder (\Program Files\App1) 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 Files\AcmeCommon, and in it a folder acme.thedll, and copy thedll.dll into \Program Files\AcmeCommon\acme.thedll

Also create a file in AcmeCommon\acme.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 its in the acme.thedll assembly, and load it from the assemblies location.

Chris Becke
Thanks for your comment.I think I replied in my earlier post that run time DLL linking is not a solution I am looking for. Side by side assmebly concept is good but that requires one to put our custom DLLs into WinSXS directory and requies admin privilege. Is there a way to maintain private store in local installation and ask all my product application to use it from the store? Is there a way to specify a directory to be used this way in manifest file?-Kartlee
Kartlee
Unfortunately not. Private side by side assembly installs are *only* searched for in the folder of the exe. I tried putting a relative path to the dll in the file node of the assembly manifest but then it failed to load. windows config files do not support the probing element of .NET style config files.
Chris Becke
Actually, as long as your OS of choice is Windows 7 or Sever 2008, you can. See the ammeded section in my reply.
Chris Becke
A: 

This may not help you, but... you CAN load dlls from arbitrary directories AND still rely on normal dynamic linking to them as long as you can control when the dlls are loaded via dynamic linking and ensure that you've already loaded the dll explicitly using a full path before it's loaded dynamically.

This is only likely to be of help if you're writing a plugin system where your plugins are dynamically linked to dlls which you wish to keep in a non standard directory. If you then know all about the dlls they're linked to you can explicitly load these dlls directly using their full path before you load the dlls (plugins) that depend on them dynamically. Since the dll is already in memory when your plugin needs to locate it it will use the version in memory. You can the unload the explicit load that you did before loading the plugin and you're good to go.

Unfortunately this wont work if your main exe needs to load dlls from arbitrary places as you cant get in ahead of the normal dll load process.

Len Holgate