Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to switch DLLs at runtime so as to use a different version?

Tags:

c#

.net

dll

I have an application which contains a number of plugins (MEF) which connect to a number of different I/O devices. Most of these plugins have a number of managed and unmanaged dlls.

One manufacturer has recently released new firmware and new drivers. The API remains the same.

I thought that I could include both dll versions in separate resource folders and copy the required set into the output folder when application starts up.

(I guess I could just make a second copy of the plugin and figure out a way of loading the correct one but I thought that copying the DLLs might be easier - especially considering that the plugin code is unchanged)

This does not work.

static MyClass() // static constructor
{
    // required version?
    if (envvar.Equals("4") )
    {
        path = "ver4.1.1";
    }
    else
    {
        path = "ver2.5.1";
    }

    // location of drivers
    path = Path.Combine("./Prj/QX", path);
    string[] files = Directory.GetFiles(path);

    // Copy the files and overwrite destination files if they already exist.
    foreach (string s in files)
    {
        string fileName = Path.GetFileName(s);
        string destFile = Path.Combine(".", fileName);
        File.Copy(s, destFile, true);
    }

    // force load of assemby
    Assembly assy = LoadWithoutCache("driver.dll");
    string fn = assy.FullName;
}

static Assembly LoadWithoutCache(string path)
{
    using (var fs = new FileStream(path, FileMode.Open))
    {
        var rawAssembly = new byte[fs.Length];
        fs.Read(rawAssembly, 0, rawAssembly.Length);
        return Assembly.Load(rawAssembly);
    }
}

The error message suggests that the original DLL was loaded or should have been loaded but could not be.

Could not load file or assembly 'driver, Version=1.5.77, Culture=neutral, PublicKeyToken=983247934' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

Is there any way to achieve my goal or do I have to build 2 separate versions of my application?

EDIT I should also say that it is not necessary to have both DLLs loaded at the same time. It would be enough to start the application with a parameter which causes one or the other DLL to be loaded.

like image 821
paul Avatar asked Apr 29 '15 08:04

paul


People also ask

How do I use two versions of the same DLL in the same project?

config. Under <runtime> , add a <codeBase> tag for each version of the DLL. This will resolve the runtime assembly loading conflict. That's it, now we can use both versions as we please.

Can two applications use the same DLL?

Solution 1 DLL's are shared resources on the same machine and can be used by multiple process on the same machine.


2 Answers

One (complicated) way to achieve this is:

1. Use a FileSystemWatcher(FSW) to watch a Folder

The FSW detects if an assembly gets changed or deleted.

2. Load an assembly into the Reflection-Only Context

Assemblies loaded into this context can only be examined! Make sure the assembly type implements the PluginInterface, by getting the types of an assembly and checking if the types implement your PluginInterface.

3. Load assembly into a seperate AppDomain using Shadow Copying

Because of the fact that you can only unload an AppDomain with all it's assemblies, you load each plugin assembly in its own AppDomain. This way the just unload the plugin's AppDomain.

Be sure to terminate all processes/threads of the plugin!

Shadow copying ensures the change of the original file by copying the assembly into a temporary path.

4. Keep track of loaded assemblies

Put the path of a successfully loaded assembly into a list. This makes it easier to detect if an assembly needs to get loaded/reloaded.

5. Handling FSW events

Check which .dll was changed/deleted to unload the assembly, or if a new assembly was detected to load it.

6. Goto step 2


Greetings, Blackanges

like image 78
er4zox Avatar answered Nov 22 '22 13:11

er4zox


You could do it in several ways. One possibility would be to use the Managed Extensibility Framework (MEF). You could even monitor a folder where the dlls reside and load a new version as soon as a new one becomes available.

The other possibility is that you can use reflection to dynamically load the dll you want during runtime.

like image 39
TheBoyan Avatar answered Nov 22 '22 15:11

TheBoyan