我们有一个使用程序集的托管应用程序。该程序集使用一些非托管 C++ 代码。
托管 C++ 代码位于一个 dll 中,它依赖于其他几个 dll。所有这些 Dll 都由此代码加载。(我们首先加载 ImageCore.dll 所依赖的所有 dll,这样我们就可以知道哪些缺失了,否则它只会显示为 ImageCore.dll 加载失败,并且日志文件不会提供有关原因的线索)。
class Interop
{
private const int DONT_RESOLVE_DLL_REFERENCES = 1;
private static log4net.ILog log = log4net.LogManager.GetLogger("Imagecore.NET");
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibraryEx(string fileName, IntPtr dummy, int flags);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr FreeLibrary(IntPtr hModule);
static private String[] libs = { "log4cplus.dll", "yaz.dll", "zlib1.dll", "libxml2.dll" };
public static void PreloadAssemblies()
{
for (int i=0; i < libs.Length; ++i) {
String libname = libs[i];
IntPtr hModule = LoadLibraryEx(libname, IntPtr.Zero, DONT_RESOLVE_DLL_REFERENCES);
if(hModule == IntPtr.Zero) {
log.Error("Unable to pre-load '" + libname + "'");
throw new DllNotFoundException("Unable to pre-load '" + libname + "'");
} else {
FreeLibrary(hModule);
}
}
IntPtr h = LoadLibraryEx("ImageCore.dll", IntPtr.Zero, 0);
if (h == IntPtr.Zero) {
throw new DllNotFoundException("Unable to pre-load ImageCore.dll");
}
}
}
这段代码由
public class ImageDoc : IDisposable {
static ImageDoc()
{
ImageHawk.ImageCore.Utility.Interop.PreloadAssemblies();
}
...
}
这是静态构造函数。
据我所知,一旦我们尝试使用 ImageDoc 对象,就会加载包含该程序集的 dll,并且作为该加载的一部分,调用静态构造函数,这反过来又会导致其他几个 DLL 被加载为出色地。我想弄清楚的是,我们如何推迟加载这些 DLL,这样我们就不会在这个由于静态构造函数而被踢出的加载程序锁中运行 smack dab。
我通过查看以下内容拼凑了这么多:
- http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/dd192d7e-ce92-49ce-beef-3816c88e5a86
- http://msdn.microsoft.com/en-us/library/aa290048%28VS.71%29.aspx
- http://forums.devx.com/showthread.php?t=53529
- http://www.yoda.arachsys.com/csharp/beforefieldinit.html
但是我似乎无法找到一种方法来加载这些外部 DLL,而不会在类加载时发生这种情况。我想我需要从静态构造函数中获取这些 LoadLibrary 调用,但不知道如何在需要它们之前调用它们(除了这里是如何完成的)。我宁愿不必将这种 dll 知识放入使用此程序集的每个应用程序中。(而且我不确定这是否能解决问题......
奇怪的是,异常似乎只在调试器内运行时发生,而不是在调试器外运行时发生。
我如何设法加载这些 DLL 而不会遇到以下问题:
LoadLibrary <- .NET loads the class from assembly dll
DllMain
LoadLibrary <- -Due to Static ctor
DllMain