2

我们有一个使用程序集的托管应用程序。该程序集使用一些非托管 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。

我通过查看以下内容拼凑了这么多:

  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
4

1 回答 1

3

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

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

(您可以在 Debug -> Exceptions 中的 Managed Debugging Assistants 部分禁用 MDA,但每次重置这些设置时,该死的 MDA 都会重新打开)

于 2010-03-19T21:19:43.027 回答