简体   繁体   English

C# 后期绑定在运行时卸载 Dll

[英]C# Late Binding Unloading Dll in Runtime

I want to load .dll into my own c# program in run-time as a plugin .If there's new update unload existing plugin dll ( InvokeHelper.dll ) and download the updated .dll ( InvokeHelper.dll ) and load it into the program without terminating the process.(my application).我想加载.dll在运行时到我自己的C#程序作为一个插件。如果有现有的插件DLL(InvokeHelper.dll)新的更新卸载和下载更新的.dll (InvokeHelper.dll),并将其装入程序而不终止进程。(我的申请)。 I read these articles to complete these task( MSDN, Article2 ) But still this code doesn't work for unloading .dll dynamically.我阅读了这些文章来完成这些任务( MSDN, Article2 )但是这段代码仍然不能用于动态卸载.dll

When I looked attached dll via process explorer attached dll is not unloaded.It's exist in process explorer dll list.I think if the dll unload success I want to manually rename the old dll and replace the new one.当我通过进程资源管理器查看附加的 dll 时,附加的 dll 没有卸载。它存在于进程资源管理器dll 列表中。我想如果 dll 卸载成功,我想手动重命名旧的 dll 并替换新的。

InvokeHelper.dll Source: InvokeHelper.dll来源:

using System;

namespace InvokeHelper
{
    public class LateBindingInvokeHelper
    {
        public void PrintHello()
        {
            using (System.IO.StreamWriter w = new System.IO.StreamWriter(@"Invoker.txt", true))
            {
                w.WriteLine(DateTime.Now.ToString());
                w.Flush();
            }
        }
    }
}

Load Dll Function:加载DLL函数:

 private AppDomain domain = null;
 private void LoadDll()
        {
            AppDomainSetup domInfo = new AppDomainSetup();
            domInfo.ApplicationBase = System.Environment.CurrentDirectory;
            Evidence adevidence = AppDomain.CurrentDomain.Evidence;
            domInfo.DisallowBindingRedirects = false;
            domInfo.DisallowCodeDownload = true;
            domain = AppDomain.CreateDomain("MyDomain", adevidence , domInfo);

            Type type = typeof(Proxy);
            var value = (Proxy)domain.CreateInstanceAndUnwrap(
                type.Assembly.FullName,
                type.FullName);

            var assembly = value.GetAssembly(@"C:\dev\ExBinder\ExBinder\bin\Debug\InvokeHelper.dll");
            Type[] mytypes = assembly.GetTypes();
            BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
            foreach (Type t in mytypes)
            {
                MethodInfo[] mi = t.GetMethods(flags); // you can change this flag , commented some flags :) view only plublic or bla bla 
                Object obj = Activator.CreateInstance(t);
                foreach (MethodInfo m in mi)
                {
                    if (m.Name.Equals("PrintHello")) m.Invoke(obj, null); //my func name :) you can set this via config :D
                }
            }
        }

    private void button2_Click(object sender, EventArgs e)
    {
        LoadDll();
        AppDomain.Unload(domain);
    }

Proxy Class代理类

public class Proxy : MarshalByRefObject
    {
        public Assembly GetAssembly(string assemblyPath)
        {
            try
            {
                return Assembly.LoadFile(assemblyPath);
            }
            catch (Exception)
            {
                return null;               
            }
        }
    }

在此处输入图片说明

The problem is that you are loading the assembly in your separate AppDomain and returning that Assembly through the proxy, so the same assembly is also loaded in your default AppDomain.问题是您正在单独的 AppDomain 中加载程序集并通过代理返回该Assembly集,因此在您的默认 AppDomain 中也加载了相同的程序集。 I have moved your invoking logic into the proxy class and its worked.我已将您的调用逻辑移到代理类中并且它起作用了。

public class Proxy : MarshalByRefObject
{
    public void Run()
    {
        var assembly = AppDomain.CurrentDomain.Load(File.ReadAllBytes(@"C:\Users\Mkrtich_Mazmanyan\Downloads\ExBinder\Exbinder\bin\Debug\InvokeHelper.dll"));

        Type[] mytypes = assembly.GetTypes();
        BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
        foreach (Type t in mytypes)
        {
            MethodInfo[] mi = t.GetMethods(flags); // you can change this flag , commented some flags :) view only plublic or bla bla elshan
            Object obj = Activator.CreateInstance(t);
            foreach (MethodInfo m in mi)
            {
                if (m.Name.Equals("PrintHello")) m.Invoke(obj, null); //my func name :) you can set this via config :D
            }
        }
    }
}

Invoking part would be:调用部分将是:

value.Run();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM