2016-12-05 7 views
0

Я пытаюсь запустить приложения через новые экземпляры AppDomain внутри моего процесса. Это для себя отлично работает, но я не могу выгрузить AppDomain, если я начал приложение WPF (при попытке его запускается исключение CannotUnloadAppDomainException). Однако выполнение консольных приложений или приложений WinForm, а затем разгрузка AppDomain работает нормально.Не удалось выгрузить 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 вы должны его выключить. Например:

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, например, если он вызывается в финализаторе ,