从另一个 WPF 应用程序加载 WPF 应用程序程序集,出现错误:无法在同一 AppDomain 中创建多个 System.Windows.Application 实例

2023-11-24

场景:

启动程序:WPF应用程序>>Build 32bit, .Net 4.5.1, location= D:\

加载程序: 另一个 WPF 应用程序 >>Build 32bit、.Net 4.5.1、location= D:\

I'm owner of both assembly(应用程序及其来源)

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

第一步我试图just load the LOADED.exe file to memory and execute it(所以我用了一个simple EXE without any resource在此步骤中)。

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 中尝试了它,然后运行...处理异常的结果:

无法在同一 AppDomain 中创建多个 System.Windows.Application 实例。

enter image description here

OK!


B)

然后,我寻找解决方案,有人说你必须在new [different] AppDomain.

例如,这是一个答案:动态加载组件 - 设置和通信

我在另一个按钮下尝试了以下代码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);
    }
}

Now my error is in this line: enter image description here

OK!


C)

我又搜索了一下,发现了这个(动态加载的程序集未加载到新的 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**:

类型为“System.TypeLoadException”的未处理异常发生于 午餐者.exe

附加信息:无法从程序集中加载类型“Main” 已加载,版本=1.0.0.0,文化=中性, 公钥令牌=空'.


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[] {});
}

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

未处理的类型异常 'System.Reflection.TargetInitationException' 发生在 mscorlib.dll 中

附加信息:目标已抛出异常 调用。


Finally:

我很困惑!

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

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


  1. 创建共享程序集。这将被加载到两个 AppDomain(“启动器”域、“已加载”域)中,并作为“已加载”AppDomain 的入口点:

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

    将以下引用添加到新项目中:System.Xaml, WindowsBase, PresentationFramework

    添加项目参考ChildDomainLoader在你的Launcher项目。这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. Use it. Call Runner.RunInOtherDomain从您的启动器应用程序。

    var assemblyPath = "path to your loaded.exe";
    ChildDomainLoader.Runner.RunInOtherDomain(assemblyPath);
    File.Delete(assemblyPath);
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从另一个 WPF 应用程序加载 WPF 应用程序程序集,出现错误:无法在同一 AppDomain 中创建多个 System.Windows.Application 实例 的相关文章

  • 如何在另一个应用程序中挂钩 api 调用

    我正在尝试挂钩另一个应用程序的 ExtTextOut 和 DrawTextExt GDI 方法调用 我知道我需要使用 GetProcAddress 来查找 gdi32 dll 中那些方法的地址 并用我的函数的地址覆盖我想要挂钩的进程中的地址
  • 在 Java 中创建 T 的新实例

    在C 中 我们可以定义一个泛型class A
  • 在 OnModelCreating 期间设置列名称

    Issue 我目前正在尝试通过设置的属性为我的表及其列添加前缀 我正在使用实体框架核心 我已经正确地为表名添加了前缀 但我似乎无法弄清楚列的前缀 我有一种感觉 我需要使用反射 我已经留下了我的 可能很糟糕的 反思尝试 有人有办法在实体中设置
  • 如何在 XAML/WPF 中存储和检索多个形状?

    使用 XAML WPF 做一些简单的事情似乎遇到了很多问题 我已经使用矩形和椭圆形等形状创建了一些基于 XAML 的图像来创建我需要应用程序的其他部分使用的图标 但我不能似乎找到了如何做到这一点 我似乎能够在资源字典中存储画布 但无法在任何
  • 从代码中,如何创建对存储在附加属性中的对象的属性的绑定?

    我们有一个继承的附加属性来存储一个对象 在可视化树的更下方 我们希望从代码绑定到该对象的属性 通常我们像这样构建绑定的路径部分 var someBinding new Binding Path new PropertyPath Attach
  • std::call_once 可重入且线程安全吗?

    std call once http en cppreference com w cpp thread call once是线程安全的 但它也是可重入的吗 我使用 VS2012 调试和发布 进行的测试表明 调用std call once从单
  • 如何使用 SOAP 且不使用 WSE 在 .NET 中签署 Amazon Web 服务请求

    亚马逊产品广告 API 以前称为 Amazon Associates Web Service 或 Amazon AWS 实施了一项新规则 即自 2009 年 8 月 15 日起 向其发送的所有 Web 服务请求都必须经过签名 他们在其网站上
  • 是否存在指向不同类型的指针具有不同大小的平台?

    C 标准允许指向不同类型的指针具有不同的大小 例如sizeof char sizeof int 是允许的 但是 它确实要求如果将指针转换为void 然后转换回其原始类型 它必须与其原始值进行比较 因此 从逻辑上来说 sizeof void
  • 为什么'enable_if'不能用于禁用这里声明

    include
  • 在 omp 并行 for 循环中使用 unique_ptr 会导致 SEG.FAULT

    采取以下代码 include
  • 将表(行)与 OpenXML SDK 2.5 保持在一起

    我想在 Word 文档中生成多个表 每行 2 行 但我想将这两行保留在一起 如果可能的话 new KeepNext 第一行不起作用 new KeepNext 第一行的最后一段不起作用 new CantSplit 放在桌子上不起作用 在所有情
  • C# 编译器不会优化不必要的强制转换

    前几天 在写答案的时候这个问题 https stackoverflow com questions 2208315 why is any slower than contains在这里 关于溢出 我对 C 编译器感到有点惊讶 它没有按照我的
  • 如何在三个 IEnumerable 上使用 Zip [重复]

    这个问题在这里已经有答案了 可能的重复 使用 Linq 从 3 个集合创建项目 https stackoverflow com questions 5284315 create items from 3 collections using
  • C#6 中的长字符串插值行

    我发现 虽然字符串插值在应用于现有代码库的字符串 Format 调用时非常好 但考虑到通常首选的列限制 字符串对于单行来说很快就会变得太长 特别是当被插值的表达式很复杂时 使用格式字符串 您将获得一个可以拆分为多行的变量列表 var str
  • 在 asp.net MVC 中使用活动目录进行身份验证

    我想使用活动目录对我的 asp net mvc 项目中的用户进行身份验证 在网上冲浪了几个小时后 我没有找到任何对我有用的东西 我已经看到了所有结果 但什么也没有 我尝试按照许多帖子的建议编辑我的 web config 如果有人可以帮助我提
  • 逆向工程 ASP.NET Web 应用程序

    我有一个 ASP NET Web 应用程序 我没有源代码 该 bin 包含 10 个程序集和一个 compiled 文件 我在 App Code dll 上使用 Reflector 它向我显示了类和命名空间之类的东西 但它太混乱了 有没有什
  • CUDA 8 编译错误 -std=gnu++11

    我正在尝试转换一些代码以使用 CUDA 并且我认为我遇到了兼容性问题 我们使用CMake 这些是我使用的 gcc 和 CUDA 版本 gcc version gcc Ubuntu 5 4 0 6ubuntu1 16 04 5 5 4 0 2
  • 在 C#.NET 中安全删除文件

    在我正在做的一个项目中 我想为用户提供 安全 删除文件的选项 例如 用随机位或 0 覆盖它 在 C NET 中是否有一种简单的方法可以做到这一点 效果如何 你可以调用系统内部删除 http technet microsoft com en
  • 如何调试 .NET 运行时中的内部错误?

    我正在尝试调试一些处理大文件的工作 代码本身works 但 NET 运行时本身会报告零星错误 对于上下文 这里的处理是一个 1 5GB 文件 仅加载到内存中一次 在循环中处理和释放 故意尝试重现此否则不可预测的错误 我的测试片段基本上是 t
  • 需要提取字符串中点后的最后一个数字,如“7.8.9.1.5.1.100”

    我需要提取 C 字符串中最后一个点后面的最后一个数字 例如 7 8 9 1 5 1 100 并将其存储在整数中 Added 该字符串也可以是 7 8 9 1 5 1 1 或 7 8 9 1 5 1 0 我还想验证它在最后一个点之前恰好是 7

随机推荐