我们有一个使用程序集的托管应用程序。该程序集使用一些非托管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运行到这个被踢出的加载器锁中。
通过查看:
,我把它拼凑在了一起但我似乎无法找到一种方法来加载这些外部DLL,而不会在类加载时发生。我想我需要从静态构造函数中获取这些LoadLibrary调用,但是不知道如何在需要它们之前调用它们(除了它在这里完成的方式)。我宁愿不必将这种dll知识放到每个使用这个程序集的应用程序中。 (而且我不确定那会解决这个问题......
奇怪的是,异常只是在调试器中运行时才出现,而不是在调试器外运行时。
如何设置加载这些DLL而不会遇到以下错误:
LoadLibrary <- .NET loads the class from assembly dll
DllMain
LoadLibrary <- -Due to Static ctor
DllMain
答案 0 :(得分:3)
LoaderLock是来自调试器的MDA(托管调试助手)警告。它告诉您可能是代码的问题。它只发生在调试器下运行时,因为正在进行MDA检查的调试器通知您在某些情况下会出现“可能”的死锁。
不幸的是,我无法帮助你。我对LoaderLock的体验是:(a)VS给你的是一个神秘的警告,但是很少有人支持你告诉你如何解决它,以及(b)我们的应用程序已经使用LoaderLock运行了4年关闭(在DirectX中,所以它甚至不在我们的代码中)并且它实际上从未引起过问题,除了每次我们在调试器下运行时都是烦人的麻烦。 YMMV当然。
(您可以在调试中禁用MDA - &gt;托管调试助手部分中的例外,但每次重置这些设置时,该死的MDA都会重新开启)