Load WPF application from the memory

拜拜、爱过 提交于 2019-11-29 14:52:54

I've found a way to do that. You basically have two options.

  1. Load the exe in the separate AppDomain.
  2. Use reflection trickery to change default ResourceAssembly.

Option first, while cleaner, has disadvantage of being slower (WPF needs to load into the new AppDomain too):

//Assembly: WpfLoader.dll
[STAThread]
class Program
{
    public class Loader : MarshalByRefObject
    {
        public void Load()
        {
            var dll = File.ReadAllBytes("WpfTest.exe");
            var assembly = Assembly.Load(dll);
            Application.ResourceAssembly = assembly;
            assembly.EntryPoint.Invoke(null, new object[0]);
        }


    }


    static void Main(string[] args)
    {
        var domain = AppDomain.CreateDomain("test");
        domain.Load("WpfLoader");

        var loader = (Loader)domain.CreateInstanceAndUnwrap("WpfLoader", "WpfLoader.Program+Loader");
        loader.Load();
    }
}

The second solution uses reflection to change ResourceAssembly of current application. You cannot do that with public API's, as the Application.ResourceAssembly is read only once it's set. You have to use reflection to access private members of both Application and ResourceUriHelper classes.

var dll = File.ReadAllBytes("WpfTest.exe");
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);

//load
assembly.EntryPoint.Invoke(null, new object[0]);

There is still a caveat with both solutions: You cannot use more than one Wpf application which uses relative resources in one AppDomain, so should you wish to load more than one app, you need to create multiple AppDomains.

For those examples to work, you need to do two things:

  • It needs to be called from single appartment state threads, so remember to use [STAThread]
  • You need to add PresentationCore.dll, PresentationFramework.dll and WindowsBase.dll references
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!