gpt4 book ai didi

c# - 从另一个 WPF 应用程序加载 WPF 应用程序程序集,在同一 AppDomain 中获取错误 : Cannot create more than one System. Windows.Application 实例

转载 作者:太空狗 更新时间:2023-10-29 23:38:32 46 4
gpt4 key购买 nike

场景:

LUNCHER.exe:一个 WPF 应用程序 >> Build 32bit, .Net 4.5.1, location= D:\

LOADED.exe:另一个 WPF 应用程序 >> Build 32bit,.Net 4.5.1,location= D:\

我是两个程序集的所有者(应用程序和thair源)

现在,我想将 LOADED.exe [及其资源,例如图像 dll 和...] 作为 Byte array 加载到内存并执行它,然后从硬盘中删除 LOADED.exe 及其资源。

在第一步中,我尝试将 LOADED.exe 文件加载到内存并执行它(所以我在此使用了一个没有任何资源的简单 EXE步骤)。

A)

好的,我为 WinForm 程序找到了这种方式 here :

var filePath = @"D:\LOADED.EXE";

if (File.Exists(filePath))
{
try
{

// prepare to load the application into memory (using Assembly.Load)

// read the bytes from the application exe file
var fs = new FileStream(filePath, FileMode.Open);
var br = new BinaryReader(fs);
byte[] bin = br.ReadBytes(Convert.ToInt32(fs.Length));
fs.Close();
br.Close();

// load the bytes into Assembly
var asm = Assembly.Load(bin);
// search for the Entry Point
var method = asm.EntryPoint;
if (method != null)
{
// create an istance of the Startup form Main method
object o = asm.CreateInstance(method.Name);

// invoke the application starting point
Application.Current.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
method.Invoke(o, null);
}
else
{
//show message: Impossible to launch the application
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message + "\n\r\n\r" + ex.InnerException + "\n\r\n\r" + "\n\r\n\r" + ex.Source);
// exception throws .. something to do?
}
}

我在一个按钮下的 LUNCHER.exe 中尝试了它,然后运行...处理异常的结果:

Cannot create more than one System.Windows.Application instance in the same AppDomain.

enter image description here

好的!


B)

然后,我搜索了一个解决方案,有人说您必须在 new [different] AppDomain 中执行它。

例如这里是一个答案:Dynamically Loaded Assembly - Settings & Communication

我在 LUNCHER.exe 的另一个按钮下尝试了以下代码:

private void Button_Click_1(object sender, RoutedEventArgs e)
{
try
{
var filePath = string.Format("{0}{1}", Utility.ExePath, PART_PATH);
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);
}
catch (Exception ex)
{
var type = "";

if (ex is ArgumentNullException)
{
type = "ArgumentNullException";
}
else if (ex is NotSupportedException)
{
type = "NotSupportedException";
}
else if (ex is AppDomainUnloadedException)
{
type = "AppDomainUnloadedException";
}
else if (ex is TypeLoadException)
{
type = "TypeLoadException";
}
else if (ex is MissingMethodException)
{
type = "MissingMethodException";
}
else if (ex is MethodAccessException)
{
type = "MethodAccessException";
}
else if (ex is BadImageFormatException)
{
type = "BadImageFormatException";
}
else if (ex is FileLoadException)
{
type = "FileLoadException";
}

MessageBox.Show(type + "\n\r\n\r" + ex.Message + "\n\r\n\r" + ex.InnerException + "\n\r\n\r" + ex.Source);
}
}

private 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 + @"LOADED.exe.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);
}

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

// Now my ERROR is in this line>>
return appDomain.CreateInstanceFromAndUnwrap(assemblyPath, method.Name);
}
else
{
return appDomain.CreateInstanceFromAndUnwrap(assemblyPath, className);
}
}

现在我的错误是在这一行: enter image description here

好的!


C)

我再次搜索并找到了这个 ( Dynamically loaded Assembly not loading in new AppDomain ):

// Provides a means of invoking an assembly in an isolated appdomain
public static class IsolatedInvoker
{
// main Invoke method
public static void Invoke(string assemblyFile, string typeName, string methodName, object[] parameters)
{
// resolve path
assemblyFile = Path.Combine(Environment.CurrentDirectory, assemblyFile);
Debug.Assert(assemblyFile != null);

// get base path
var appBasePath = Path.GetDirectoryName(assemblyFile);
Debug.Assert(appBasePath != null);

// change current directory
var oldDirectory = Environment.CurrentDirectory;
Environment.CurrentDirectory = appBasePath;
try
{
// create new app domain
var domain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, appBasePath, null, false);
try
{
// create instance
var invoker = (InvokerHelper) domain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, typeof(InvokerHelper).FullName);

// invoke method
var result = invoker.InvokeHelper(assemblyFile, typeName, methodName, parameters);

// process result
Debug.WriteLine(result);
}
finally
{
// unload app domain
AppDomain.Unload(domain);
}
}
finally
{
// revert current directory
Environment.CurrentDirectory = oldDirectory;
}
}

// This helper class is instantiated in an isolated app domain
private class InvokerHelper : MarshalByRefObject
{
// This helper function is executed in an isolated app domain
public object InvokeHelper(string assemblyFile, string typeName, string methodName, object[] parameters)
{
// create an instance of the target object
var handle = Activator.CreateInstanceFrom(assemblyFile, typeName);

// get the instance of the target object
var instance = handle.Unwrap();

// get the type of the target object
var type = instance.GetType();

// invoke the method
var result = type.InvokeMember(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, instance, parameters);

// success
return result;
}
}
}

然后我在 LUNCHER.exe 的另一个按钮下通过以下代码调用它:

private void Button_Click_2(object sender, RoutedEventArgs e)
{
var filePath = string.Format("{0}{1}", Utility.ExePath, PART_PATH);
IsolatedInvoker.Invoke(filePath, "Main", "Main", new object[] {});
}

但是我得到了和以前一样的错误 **B**:

An unhandled exception of type 'System.TypeLoadException' occurred in Luncher.exe

Additional information: Could not load type 'Main' from assembly Loaded, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.


D)

我还在 LUNCHER.EXE 中的另一个按钮下以这种方式进行了测试:

private void Button_Click_3(object sender, RoutedEventArgs e)
{
var filePath = @"D:\LOADED.exe";
var dll = File.ReadAllBytes(filePath);
var assembly = Assembly.Load(dll);

var app = typeof (Application);

var field = app.GetField("_resourceAssembly", BindingFlags.NonPublic | BindingFlags.Static);
field.SetValue(null, assembly);

//fix urihelper
var helper = typeof (BaseUriHelper);
var property = helper.GetProperty("ResourceAssembly", BindingFlags.NonPublic | BindingFlags.Static);
property.SetValue(null, assembly, null);

//---- Now my ERROR is in this line >>
assembly.EntryPoint.Invoke(null, new object[] {});
}

运行时最后一行代码错误:

An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

Additional information: Exception has been thrown by the target of an invocation.


最后:

我很困惑!

  • 我在上述所有方法中的错误是什么?
  • 为什么所有的方法都以错误结尾!!!

请用简单的描述和一些代码帮助我,因为我在这种情况下是初学者(加载程序集,创建 AppDomain 和......)但我需要将 WPF 应用程序加载到内存中并且显示它的窗口,然后在它在内存中运行时从 H.D.D 中删除它的文件。

最佳答案

  1. 创建一个共享程序集。这将加载到两个 AppDomains(“Launcher”域、“Loaded”域)并作为我们“Loaded”AppDomain 的入口点:

    添加新项目 > 类库 > 名称:ChildDomainLoader

    在新项目中添加以下引用:System.XamlWindowsBasePresentationFramework

    在您的 Launcher 项目中为 ChildDomainLoader 添加项目引用。 Loaded 项目无需修改。

  2. 向共享程序集添加一些代码。我们需要一个可以跨域调用并加载我们的子程序集的 MarshalByRefObject。我们称它为 Runner:

    using System;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Windows;

    namespace ChildDomainLoader
    {
    public class Runner : MarshalByRefObject
    {
    public static AppDomain RunInOtherDomain(string assemblyPath)
    {
    var ownType = typeof (Runner);
    string ownAssemblyName = ownType.Assembly.FullName;

    // Create a new AppDomain and load our assembly in there.
    var childDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
    childDomain.Load(ownAssemblyName);

    // Call Run() in other AppDomain.
    var runner = (Runner) childDomain.CreateInstanceAndUnwrap(ownAssemblyName, ownType.FullName);
    runner.Run(assemblyPath);

    return childDomain;
    }

    public void Run(string assemblyPath)
    {
    // We load the assembly as byte array.
    var otherAssemblyBytes = File.ReadAllBytes(assemblyPath);
    var assembly = AppDomain.CurrentDomain.Load(otherAssemblyBytes);

    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
    throw new NotImplementedException("Probably need to do some work here if you depend on other assemblies.");
    };

    // Set the assembly as ResourceAssembly, as WPF will be confused otherwise.
    Application.ResourceAssembly = assembly;

    // Search for the App class.
    var app = assembly
    .GetExportedTypes()
    .Single(t => typeof(Application).IsAssignableFrom(t));

    // Invoke its Main method.
    MethodInfo main = app.GetMethod("Main", BindingFlags.Static | BindingFlags.Public);
    main.Invoke(null, null);
    }
    }
    }
  3. 使用它。从您的 Launcher 应用程序调用 Runner.RunInOtherDomain

    var assemblyPath = "path to your loaded.exe";
    ChildDomainLoader.Runner.RunInOtherDomain(assemblyPath);
    File.Delete(assemblyPath);

关于c# - 从另一个 WPF 应用程序加载 WPF 应用程序程序集,在同一 AppDomain 中获取错误 : Cannot create more than one System. Windows.Application 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27328200/

46 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com