动态加载程序集-设置&沟通

本文关键字:沟通 设置 加载 程序集 动态 | 更新日期: 2023-09-27 18:15:27

那么…我有一个WPF应用程序(我们称其为Launcher.exe),它动态加载并执行另一个WPF应用程序(我们称其为Loaded.exe),如下所示:

Byte[] assemblyData;
using (BinaryReader reader = new BinaryReader(new FileStream(filePath, FileMode.Open)))
    assemblyData = reader.ReadBytes(Convert.ToInt32(fs.Length));
Assembly assembly = Assembly.Load(assemblyData);
MethodInfo method = assembly.EntryPoint;
if (method != null)
{
    Object instance = assembly.CreateInstance(method.Name);
    method.Invoke(o, null);
}

现在…问题是Launched.exe在文件Loaded.exe.config中有自己的设置,并且它也在绑定中使用它们。例如:

Topmost="{Binding Mode=TwoWay, Path=Topmost, Source={x:Static p:Settings.Default}}"

第一个问题是,我如何使我的动态加载程序集正确加载/绑定/更新,更一般地说,使用自己的设置?我不认为它能自动处理这个…

第二个问题是:Loaded.exe可以和Launcher.exe通信吗?假设Loaded.exe需要一些只有Launcher.exe才能检索到的数据…它怎么能要求呢?我想我需要像两个程序集之间的代理,但我甚至不知道如何开始编码这个…

动态加载程序集-设置&沟通

我想你需要加载一个单独的程序集与它自己的。config文件,不是吗?我这样做的一种方法是在一个新的AppDomain中加载程序集。您可以将该程序集部署在一个单独的文件夹中,其中包含所有需要的引用。

首先设置AppDomain,这里有一个方法:

AppDomain getAppDomainForAssembly(string assemblypath, string appdomainname) 
    {
        //this._assembly_file = AssemblyFile;
        string _assembly_file_name = System.IO.Path.GetFileName(assemblypath);
        string _rootpath = System.IO.Path.GetDirectoryName(assemblypath);
        //this._assembly_class_name = AssemblyClassNameToInstance;
        AppDomainSetup _app_domain_info = new AppDomainSetup();
        _app_domain_info.ApplicationBase = _rootpath;
        _app_domain_info.PrivateBinPath = _rootpath;
        _app_domain_info.PrivateBinPathProbe = _rootpath;
        _app_domain_info.ConfigurationFile = _rootpath + @"'app.config"; //Here put the path to the correct .assembly .config file
        AppDomain _app_domain = AppDomain.CreateDomain(
            appdomainname, null, _app_domain_info);
        return _app_domain;
    }

然后获取在程序集中执行该方法的对象的实例:

protected System.Reflection.Assembly _asm_resolve(string assemblyFile)
    {
        return System.Reflection.Assembly.LoadFrom(assemblyFile);
    }
object getInstanceFromAppDomain(ref AppDomain appDomain, 
  string assemblyPath, string className = null) 
    {
        if (string.IsNullOrEmpty(className))
        {
            System.Reflection.Assembly assembly = _asm_resolve(assemblyPath);
            System.Reflection.MethodInfo method = assembly.EntryPoint;
            return appDomain.CreateInstanceFromAndUnwrap(assemblyPath, method.Name);
        }
        else 
        {
            return appDomain.CreateInstanceFromAndUnwrap(assemblyPath, className);
        }
    }

即使知道对象类型,也可以创建泛型方法:

T getInstanceFromAppDomain<T>(ref AppDomain appDomain, 
 string assemblyPath, string className = null) 
    {
        if (string.IsNullOrEmpty(className))
        {
            System.Reflection.Assembly assembly = _asm_resolve(assemblyPath);
            System.Reflection.MethodInfo method = assembly.EntryPoint;
            return (T)appDomain.CreateInstanceFromAndUnwrap(assemblyPath, method.Name);
        }
        else 
        {
            return (T)appDomain.CreateInstanceFromAndUnwrap(assemblyPath, className);
        }
    }

然后,调用在新appDomain中执行的已创建实例上的方法:

void executeMethod(Type objecttype, string methodname, ref object instancedObject, object[] methodparams) 
    {
        objecttype.InvokeMember(
            methodname, System.Reflection.BindingFlags.InvokeMethod, null, instancedObject, methodparams);
    }

你可以这样写:

AppDomain newappdomain = getAppDomainForAssembly(filePath, "Loaded.exe.domain");
        object loadedexe_object = getInstanceFromAppDomain(ref newappdomain,
            filePath);
        //If you know the method name to call...
        executeMethod(loadedexe_object.GetType(), "methodname", ref loadedexe_object, null);
        //or get entry point...
        executeMethod(loadedexe_object.GetType(),
            _asm_resolve(filePath).EntryPoint.Name, ref loadedexe_object, null);

对于第二个问题,你可以使用NamedPipes, Remoting, WCF…您需要在同一台机器上实现进程间通信。请查看MSDN文档,其中包含了使用WCF实现此场景的代码示例http://msdn.microsoft.com/en-us/library/system.servicemodel.netnamedpipebinding.aspx

请参阅CodeProject上使用Remoting的示例通过Remoting进行进程间通信