Dynamically loaded assembly - settings and communication

Okay, so ... I have a WPF application (call it Launcher.exe ) that downloads and runs another WPF application (let it be called 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); } 

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

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

First question: how can I make my dynamically loaded assembly load correctly / bind / update and, more generally, use my own settings? I don't think he can handle this automatically ...

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

+2
source share
1 answer

I suppose you will need to load a separate assembly with your own .config file, no? One way to do this is to load the assembly into the new AppDomain. You can deploy this assembly in a separate folder with all the necessary links.

First configure 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 build method:

 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 type of an object, we can create a method with a common 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); } } 

And then the method of the created instance is called, which is executed 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); } 

You can use the following:

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

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

See this example in CodeProject using Remoting Inter-process communication via Remoting

+1
source

Source: https://habr.com/ru/post/1208476/


All Articles