动态加载的程序集 - 设置 &沟通 [英] Dynamically Loaded Assembly - Settings & Communication

查看:26
本文介绍了动态加载的程序集 - 设置 &沟通的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的...我有一个 WPF 应用程序(我们称之为 Launcher.exe),它加载并执行另一个 WPF 应用程序(我们称之为 Loaded.exe)动态使用这样的东西:

Ok so... I have a WPF application (let's call it Launcher.exe) which loads and executes another WPF application (let's call it Loaded.exe) dynamically using something like this:

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 中有它自己的设置,并且它也在绑定中使用它们.例如:

Now... the problem is that Launched.exe has its own settings in the file Loaded.exe.config, and it also uses them in bindings. For example:

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

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

First question is, how can I make my dynamically loaded assembly properly load/bind/update and, more generally, use its own settings? I don't think it can handle this automagically...

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

Second question is: can Loaded.exe communicate with Launcher.exe? Let's say Loaded.exe needs some data that only Launcher.exe can retrieve... how can it ask for it? I think I need something like a proxy between the two assemblies, but I can't even figure out how to start coding this...

推荐答案

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

I supose you'll need to load a separate assembly with it's own .config file, no? One way i do that is to load the assembly in a new AppDomain. You'll could deploy that assembly in a separate folder with all his needed references.

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

First setup the AppDomain, here you have a method:

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

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

Then get an instance of the object that executes the method on the assembly:

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

        }
    }

即使我们知道对象类型,我们也可以创建一个具有泛型类型的方法:

Even if we know the Object Type, we could create a method with generic type:

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 中执行:

And then, invoke the method on the created instance, wich is executing in the new 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

For the second question, you could use NamedPipes, Remoting, WCF... You need to implement interprocess communication on the same machine. Take a look at MSDN documentaion, code sample covering this scenario with WCF http://msdn.microsoft.com/en-us/library/system.servicemodel.netnamedpipebinding.aspx

使用远程处理在 CodeProject 上查看此示例通过远程处理的进程间通信

See this sample on CodeProject, using Remoting Inter-process communication via Remoting

这篇关于动态加载的程序集 - 设置 &amp;沟通的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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