我正在开发一个项目,我们正在使用 Crypto Obfuscator 将多个 DLL 嵌入到单个 DLL 中。然后 DLL 在另一个项目中动态加载到它自己的应用程序域中。大多数嵌入式 DLL 似乎都能正常工作。但是,任何包含主 DLL 类继承的类的嵌入式 DLL 都不能正确加载。我让它工作的唯一方法是将DLL留在目录中(这违背了嵌入它们的目的)。
例如:
我有四个不同的 DLL:MyLibrary、MyLibrary2、MyProgram 和 MyInterfaces
MyLibrary DLL 中的MyClass1类继承自 MyInterfaces DLL 内部的接口ClassInterface。
MyLibrary2 DLL 中的MyClass2类继承自MyClass1。Crypto Obfuscator 用于在 MyLibrary2 DLL 中嵌入 DLL:MyInterfaces 和 MyLibrary。
MyProgram DLL 中的 MyProgramClass类具有对 MyInterfaces DLL 的引用,并使用它来动态创建MyClass2的实例。
当程序运行时,它会抱怨它在尝试创建 MyClass2 的实例时找不到程序集 MyLibrary。
无法加载文件或程序集“MyLibrary,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”或其依赖项之一。该系统找不到指定的文件。
任何想法如何解决这个问题?
我的接口 DLL:
namespace MyInterfaces
{
public interface ClassInterface
{
string Get();
}
}
我的图书馆 DLL:
namespace MyLibrary
{
public class MyClass : MarshalByRefObject, ClassInterface
{
public string Get()
{
return "2.0.0.0";
}
}
}
MyLibrary2 DLL:
namespace MyLibrary2
{
public class MyClass2 : MyClass, ClassInterface
{
public string Get()
{
return base.Get();
}
}
}
我的程序 DLL:
namespace MyProgram
{
public class MyProgramClass
{
public MyProgramClass()
{
try
{
string typeName = "MyLibrary2.MyClass2";
string appDomainName = "MyLibrary2";
ClassInterface c2 = CreateInstance(@"X:\Temp\MyLibrary2.dll", typeName, appDomainName);
if (c2 == null) return;
MessageBox.Show(c2.Get());
}
catch
{
MessageBox.Show(":(");
}
}
private ClassInterface CreateInstance(string filePath, string typeName, string appDomainName)
{
try
{
AppDomainSetup appDomainSetup = new AppDomainSetup();
FileInfo fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists) return null;
appDomainSetup.PrivateBinPath = string.Format("{0}", fileInfo.Directory.FullName);
appDomainSetup.PrivateBinPathProbe = "True";
appDomainSetup.ApplicationBase = fileInfo.Directory.FullName;
appDomainSetup.ApplicationTrust = AppDomain.CurrentDomain.ApplicationTrust;
Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
AppDomain appDomain = AppDomain.CreateDomain(appDomainName, evidence, appDomainSetup);
string assemblyName = Path.GetFileNameWithoutExtension(fileInfo.FullName);
return appDomain.CreateInstanceAndUnwrap(assemblyName, typeName) as ClassInterface;
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return null;
}
}
}
更新 1
我已经研究过使用 AssemblyResolve 事件。我试图在我的测试应用程序中实现它,看看我是否可以让它工作。我在 AssemblyResolve 事件中放置了一个断点,但是它永远不会被命中并且仍然会抛出错误。如果我将MyClass2设置为不从MyClass1继承,我的断点会被命中并正确执行。
附带说明一下,在包含嵌入式 DLL 的 DLL 上使用 JustDecompile,似乎 Crypto Obfuscator 在 DLL 的默认命名空间中设置了此事件。
我曾经使用以下链接来实现 AssemblyResolve 事件:http: //blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-第三版.aspx
MyLibrary2 DLL 更改:
namespace MyLibrary2
{
public class MyClass2 : MyClass, ClassInterface
{
static MyClass2()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
String resourceName = string.Format("{0}.{1}.dll", "MyLibrary2", new AssemblyName(args.Name).Name);
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
public string Get()
{
return base.Get();
}
}
}