2016-06-07 82 views
3

我加载一个函数到新创建的AppDomain并且所有的工作都很好,但是如果我关闭程序然后重新命名并重新启动它,那么我会有FileNotFound异常。我只是不明白,那怎么可能?AppDomain DoCallBack FileNotFound异常

错误(appDomainProject原来的程序名)

System.IO.FileNotFoundException: Could not load file or assembly "appDomainProject, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null" or one of its dependencies. Can not find the file specified. 

来源

using System; 
using System.IO; 
using System.Windows.Forms; 

namespace appDomainProject 
{ 
    static class Program 
    { 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 

      try 
      { 
       AppDomain authDomain = AppDomain.CreateDomain(DateTime.Now.ToString()); 
       authDomain.DoCallBack(load_Auth); 
      } 
      catch (Exception ex) 
      { 
       File.WriteAllText("e.txt", ex.ToString());; 
       MessageBox.Show(ex.ToString()); 
      } 
     } 

     private static void load_Auth() 
     { 
      MessageBox.Show("AUTH"); 
     } 
    } 
} 
+0

只是可以肯定的:“关闭程序并重新命名“,你的意思是你正在重命名exe文件,不涉及重建,没有在GAC或NGen等中注册? – dlatikay

+0

yeap,只需重新命名而不需重建 – SLI

+0

即可重现。源代码行21,DoCallBack失败。有趣的是,看起来像这样的一个重复的Q,被删除从SO:http://stackoverflow.com/questions/30512932/execute-code-in-appdomain-in-renamed-executables – dlatikay

回答

2

我猜exe我们有一些类型的关于他们的硬编码的名字。事实上,如果你检查typeof(Program).AssemblyName这是原来的名字,这就是我期望我们得到错误的原因。

但是,您始终可以手动将DLL加载到AppDomain中,然后在那里有一些类,用于拦截“原始”名称的请求并将其替换为正确的程序集。

此代码是:

/// <summary> 
/// It seems that if you rename an exe and then try to load said 
/// assembly into a separate app-domain, .NET looks for the original 
/// name. This class loads the current assembly into the app 
/// domain manually and then detects request for the original name 
/// and redirects it to the correct assembly. 
/// 
/// http://stackoverflow.com/questions/37685180 
/// </summary> 
public class RenamedExeFixer : MarshalByRefObject 
{ 
    /// <summary> Load the assembly that this type is in into the app-domain. </summary> 
    public static void LoadOriginatingAssemblyIntoDomain(AppDomain appDomain) 
    { 
    var pathToSelf = new Uri(typeof(RenamedExeFixer).Assembly.CodeBase).LocalPath; 
    appDomain.Load(File.ReadAllBytes(pathToSelf)); 

    // create an instance of the class inside of the domain 
    // so that it can hook into the AssemblyResolve event 
    appDomain.CreateInstanceFrom(pathToSelf, typeof(RenamedExeFixer).FullName); 
    } 

    private readonly string _myAssemblyName; 

    public RenamedExeFixer() 
    { 
    // cached for efficiency (probably not needed) 
    _myAssemblyName = typeof(RenamedExeFixer).Assembly.FullName; 

    AppDomain.CurrentDomain.AssemblyResolve += HandleAssemblyResolve; 
    } 

    private Assembly HandleAssemblyResolve(object sender, ResolveEventArgs args) 
    { 
    if (args.Name == _myAssemblyName) 
    { 
     return typeof(RenamedExeFixer).Assembly; 
    } 

    return null; 
    } 
} 

然后所有你需要做的是调用辅助方法创建的应用程序域后:

AppDomain authDomain = AppDomain.CreateDomain(DateTime.Now.ToString()); 
RenamedExeFixer.LoadOriginatingAssemblyIntoDomain(authDomain); 
authDomain.DoCallBack(load_Auth); 
0

对不起,这是由设计...

作为一种解决方法,你可以移动方法添加到外部DLL,因此您可以重命名.exe。

如果你希望你的应用程序只有一个文件,你可以使用ILmerge

+0

有没有“设计”的来源? – FriendlyGuy

+0

@MackieChan没有文档,但如果你看看.net代码,并且你想到什么是Docallback。它需要存储的exe的名称做跨应用程序调用 – giammin

+0

嗯,我认为发生的事情是它存储程序集名称,这是最初的exe名称(可能是因为.NET exes的存储方式)。因此,当它加载组件时,它不能正确解决它。我不知道我是否会说这是通过设计,而是说它是.NET退出方式的一个副作用(如果我的理论是正确的)。 – FriendlyGuy

相关问题