如何在同一进程与AppDomain中通过反射加载并运行WPF EXE?解决TinyJitHook加载时无法定位XAML资源的问题
解决同一进程加载WPF EXE时的"Cannot locate resource 'mainwindow.xaml'"错误
这个问题的核心原因是:当你通过Assembly.LoadFrom加载外部WPF程序集时,WPF的资源查找机制默认会使用当前宿主进程的AppDomain基目录/工作目录,而不是WPF EXE文件所在的目录。这就导致WPF无法找到嵌入在目标程序集里的XAML资源文件。
下面是几个可行的解决方案,结合你的TinyJitHook场景来调整:
方案1:修改AppDomain的应用基目录
在加载WPF程序集之前,把AppDomain的基目录设置为WPF EXE所在的路径,让WPF资源系统能正确定位到资源:
public static void Main(string[] args) { string filePath = @"WpfApp1.exe"; string wpfExeFullPath = Path.GetFullPath(filePath); string wpfExeDir = Path.GetDirectoryName(wpfExeFullPath); // 临时修改AppDomain的应用基目录为WPF EXE所在目录 string originalAppBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; AppDomain.CurrentDomain.SetData("APPBASE", wpfExeDir); Assembly asm = Assembly.LoadFrom(wpfExeFullPath); MainJitHook hook = new MainJitHook(asm, IntPtr.Size == 8); hook.OnCompileMethod += ChangeExample; hook.Hook(); try { MethodInfo method = asm.EntryPoint; method.Invoke(null, new object[] { }); } catch (Exception extInfo) { Console.WriteLine(extInfo.ToString()); } finally { // 恢复原来的应用基目录 AppDomain.CurrentDomain.SetData("APPBASE", originalAppBase); hook.Unhook(); } Console.WriteLine("DONE"); Console.ReadKey(); }
方案2:手动初始化WPF Application并指定资源程序集
如果修改AppDomain基目录会影响你的控制台程序逻辑,可以手动创建WPF Application实例,强制指定资源程序集为加载的WPF程序集:
public static void Main(string[] args) { string filePath = @"WpfApp1.exe"; Assembly asm = Assembly.LoadFrom(filePath); MainJitHook hook = new MainJitHook(asm, IntPtr.Size == 8); hook.OnCompileMethod += ChangeExample; hook.Hook(); try { // 获取WPF的App类型 Type appType = asm.GetType("WpfApp1.App"); if (appType != null) { // 创建Application实例 Application app = (Application)Activator.CreateInstance(appType); // 强制设置资源程序集为加载的WPF程序集 Application.ResourceAssembly = asm; // 手动启动应用(替代直接调用EntryPoint) app.Run(); } } catch (Exception extInfo) { Console.WriteLine(extInfo.ToString()); } hook.Unhook(); Console.WriteLine("DONE"); Console.ReadKey(); }
补充说明
- 为什么
Process.Start能正常运行?因为它是启动了一个独立的进程,WPF的资源系统会自动使用该进程的基目录(即WPF EXE所在目录)来查找资源,所以不会出错。 - 如果你需要保留原有的EntryPoint调用方式,方案1会更直接;如果希望更精细地控制WPF应用的初始化,方案2更灵活。
- 注意:在多程序集场景下,可能还需要处理
AppDomain.CurrentDomain.AssemblyResolve事件,确保WPF依赖的其他程序集能被正确加载。
内容的提问来源于stack exchange,提问作者SkyStar
相关产品推荐
相关产品推荐

