2

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). I read these articles to complete these task(MSDN, Article2) But still this code doesn't work for unloading .dll dynamically.

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.

InvokeHelper.dll Source:

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:

 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;               
            }
        }
    }

enter image description here

Community
  • 1
  • 1
Elshan
  • 7,339
  • 4
  • 71
  • 106

1 Answers1

2

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. 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();

Mike
  • 3,766
  • 3
  • 18
  • 32