2016-12-05 77 views
0

我試圖通過我的進程中新的AppDomain實例啓動應用程序。這本身工作正常,但我無法卸載AppDomain,如果我開始一個WPF應用程序(CannotUnloadAppDomainException拋出,如果嘗試它)。執行控制檯應用程序或WinForm應用程序,然後卸載AppDomain工作正常。在運行wpf應用程序後無法卸載AppDomain

這是我使用來設置類「InternalExecutableChecker」的應用程序域和觸發代碼的代碼:

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 App正確卸載域,您必須關閉它。 例如:

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:

在某些情況下,調用卸載會導致立即CannotUnloadAppDomainException,例如,如果它被稱爲終結。