我们有一个使用程序集的托管应用程序。该程序集使用一些非托管 C++ 代码。

托管 C++ 代码位于 dll 中,该 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 的加载,这样我们就不会直接运行到由于静态构造函数而被踢出的加载器锁中。

我通过查看以下内容将这些内容拼凑在一起:

  1. http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/dd192d7e-ce92-49ce-beef-3816c88e5a86
  2. http://msdn.microsoft.com/en-us/library/aa290048%28VS.71%29.aspx
  3. http://forums.devx.com/showthread.php?t=53529
  4. 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
有帮助吗?

解决方案

LoaderLock 是一个 MDA(托管调试助手) 警告 来自调试器。它告诉你,有 可能 是代码有问题。仅当在调试器下运行时才会发生这种情况,因为调试器正在进行 MDA 检查以通知您在某些情况下会出现死锁”可能 发生”。

不幸的是,我无法为您提供更多帮助。我对 LoaderLock 的体验是:(a) 这是 VS 给你的一个神秘警告,但几乎没有什么支持告诉你实际应该做什么来解决它,(b) 我们的应用程序已经使用 LoaderLock 运行了 4 年关闭(在 DirectX 中,所以它甚至不在我们的代码中)并且它实际上从未引起问题,除了每次在调试器下运行时都会带来烦人的麻烦。当然是YMMV。

(您可以在“托管调试助手”部分的“调试”->“异常”中禁用 MDA,但每次重置这些设置时,该死的 MDA 都会重新打开)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top