在其中运行 wpf 应用程序后无法卸载 AppDomain
Posted
技术标签:
【中文标题】在其中运行 wpf 应用程序后无法卸载 AppDomain【英文标题】:Unable to unload an AppDomain after running wpf application in it 【发布时间】:2016-12-05 11:16:12 【问题描述】:我正在尝试通过进程中的新 AppDomain 实例启动应用程序。这本身工作正常,但如果我启动 WPF 应用程序,我将无法卸载 AppDomain(如果尝试它,则会引发 CannotUnloadAppDomainException)。执行控制台应用程序或 WinForm 应用程序然后卸载 AppDomain 工作正常。
这是我用来设置“InternalExecutableChecker”类的 AppDomain 和触发代码的代码:
var manager = new AppDomainManager();
var setup = new AppDomainSetup
ApplicationBase = Path.GetDirectoryName(executablePath),
LoaderOptimization = LoaderOptimization.MultiDomainHost
;
AppDomain domain = manager.CreateDomain(Path.GetFileNameWithoutExtension(executablePath), null, setup);
try
domain.Load(Assembly.GetExecutingAssembly().FullName);
var checker = (InternalExecutableChecker)domain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(InternalExecutableChecker).FullName);
Logger.Info(checker.Check(executablePath));
finally
AppDomain.Unload(domain);
这是在另一个域内执行的 InternalExecutableChecker 类的代码(设置并启动一个加载要执行的程序集的 STA 线程,将其设置为该域的入口程序集,然后调用入口方法) .
public class InternalExecutableChecker : MarshalByRefObject
private readonly object _lock = new object();
private string _result;
public string Check(string executablePath)
var thread = new Thread(() => InternalCheck(executablePath)) Name = AppDomain.CurrentDomain.FriendlyName ;
thread.SetApartmentState(ApartmentState.STA);
lock (_lock)
thread.Start();
Monitor.Wait(_lock);
return _result;
private void InternalCheck(string executablePath)
try
Assembly assembly;
try
assembly = Assembly.LoadFrom(executablePath);
catch (BadImageFormatException)
_result = "No 32 bit .NET application";
return;
try
ModifyEntryAssembly(assembly);
assembly.EntryPoint.Invoke(null, new object[] );
catch (Exception e)
_result = e.Message;
if (_result == null)
_result = "OK";
finally
lock (_lock)
Monitor.Pulse(_lock);
private void ModifyEntryAssembly(Assembly assembly)
AppDomainManager manager = new AppDomainManager();
FieldInfo entryAssemblyfield = manager.GetType().GetField("m_entryAssembly", BindingFlags.Instance | BindingFlags.NonPublic);
if (entryAssemblyfield == null)
throw new Exception("Could not retrieve entryAssemblyField.");
entryAssemblyfield.SetValue(manager, assembly);
AppDomain domain = AppDomain.CurrentDomain;
FieldInfo domainManagerField = domain.GetType().GetField("_domainManager", BindingFlags.Instance | BindingFlags.NonPublic);
if (domainManagerField == null)
throw new Exception("Could not retrieve domainManagerField.");
domainManagerField.SetValue(domain, manager);
【问题讨论】:
【参考方案1】:要使用 Wpf 应用程序正确卸载域,您必须关闭它。 例如:
CrossAppDomainDelegate action = () =>
App app = null;
Thread thread = new Thread(() =>
app = new App();
app.MainWindow = new MainWindow();
app.MainWindow.Show();
app.Run();
);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Task.Delay(TimeSpan.FromSeconds(1)).ContinueWith(_ =>
app.Dispatcher.Invoke(()=>app.Shutdown());
);
;
什么时候:
domain.DoCallBack(action);
...
AppDomain.Unload(domain);
来自 MSDN 的注释:
在某些情况下,调用 Unload 会立即引发 CannotUnloadAppDomainException,例如在终结器中调用它时。
【讨论】:
以上是关于在其中运行 wpf 应用程序后无法卸载 AppDomain的主要内容,如果未能解决你的问题,请参考以下文章