2016-12-05 19 views
0

私のプロセス内で新しいAppDomainインスタンスを介してアプリケーションを起動しようとしています。これ自体は問題なく動作しますが、WPFアプリケーションを起動した場合はAppDomainをアンロードできません(試してみるとCannotUnloadAppDomainExceptionがスローされます)。コンソールアプリケーションやWinFormアプリケーションを実行してから、AppDomainをアンロードするとうまくいきます。wpfアプリケーションを実行した後にAppDomainをアンロードできない

これは、セットアップに私が使用しているコードの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を引き起こし。

関連する問題