是否可以在运行时切换DLL以便使用不同的版本? [英] Is it possible to switch DLLs at runtime so as to use a different version?

查看:257
本文介绍了是否可以在运行时切换DLL以便使用不同的版本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,其中包含许多连接到多个不同I / O设备的插件(MEF)。大多数这些插件都有一些管理和非托管的DLL。



一家制造商最近发布了新的固件和新的驱动程序。 API保持不变。



我以为可以将两个dll版本包含在单独的资源文件夹中,并在应用程序启动时将所需的集合复制到输出文件夹中。 p>

我想我可以做一个插件的第二个副本,并找出一个加载正确的方法,但我认为复制DLL可能会更容易 - 特别是考虑到插件代码不变



这不起作用。

  static MyClass()//静态构造函数
{
//必需版本?
if(envvar.Equals(4))
{
path =ver4.1.1;
}
else
{
path =ver2.5.1;
}

//驱动程序的位置
path = Path.Combine(./ Prj / QX,path);
string [] files = Directory.GetFiles(path);

//复制文件并覆盖目标文件(如果它们已经存在)。
foreach(文件中的字符串)
{
string fileName = Path.GetFileName(s);
string destFile = Path.Combine(。,fileName);
File.Copy(s,destFile,true);
}

//强制装载
装配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);
}
}

错误消息表明原始DLL已加载或应该已经加载但不能。

 无法加载文件或程序集驱动程序,版本= 1.5.77,文化=中性,PublicKeyToken = 983247934'或其依赖关系之一。找到的程序集的清单定义与程序集引用不匹配。 (HRESULT的异常:0x80131040)

有没有办法实现我的目标,或者我必须建立我的应用程序的2个独立版本?



编辑
我还应该说,没有必要在两个DLL中加载同时。使用一个引用一个或另一个DLL的参数启动应用程序就足够了。

解决方案

一个(复杂的)实现这一点的方法是:



1。使用FileSystemWatcher(FSW)来查看文件夹



FSW检测是否有程序集被更改或删除。



2。将程序集加载到仅反思上下文



加载到此上下文中的程序集只能被检查!
确保程序集类型实现PluginInterface,通过获取程序集的类型并检查类型是否实现您的PluginInterface。



3。使用影子复制



由于您只能卸载所有它的程序集的AppDomain,所以将每个插件程序集加载到自己的AppDomain中。这样就可以卸载插件的AppDomain。



确保终止插件的所有进程/线程!



影子复制确保原始将该程序集复制到临时路径中。



4。跟踪加载的程序集



将成功加载的程序集的路径放入列表中。
这样可以更容易地检测是否需要加载/重新加载程序集。



5。处理FSW事件



检查哪个.dll被更改/删除以卸载程序集,或者检测到新程序集加载。



6。转到步骤2






问候,
黑橙


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.

解决方案

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

这篇关于是否可以在运行时切换DLL以便使用不同的版本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆