Как избежать блокировки загрузчика? - PullRequest
2 голосов
/ 20 марта 2010

У нас есть управляемое приложение, которое использует сборку. Эта сборка использует некоторый неуправляемый код C ++.

Управляемый код C ++ находится в dll, что зависит от нескольких других dll. Все эти Dll загружены этим кодом. (Мы загружаем все библиотеки DLL, от которых зависит ImageCore.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

1 Ответ

3 голосов
/ 20 марта 2010

LoaderLock - это MDA (Managed Debugging Assistant) предупреждение от отладчика. Он говорит вам, что может быть проблема с кодом. Это происходит только при работе под отладчиком, потому что именно отладчик выполняет проверки MDA, чтобы сообщить вам, что при некоторых обстоятельствах может возникнуть тупик " может ".

К сожалению, я не могу помочь вам намного дальше, чем это. Мой опыт работы с LoaderLock заключается в том, что (а) это загадочное предупреждение, которое дает вам VS, но очень мало поддержки, сообщающей вам, что на самом деле нужно сделать, чтобы решить эту проблему, и (б) наше приложение работало в течение 4 лет с LoaderLock отключение (в DirectX, так что его даже нет в нашем коде), и это на самом деле никогда не вызывало проблем, кроме того, что надоедала, каждый раз, когда мы запускаемся под отладчиком. YMMV конечно.

(Вы можете отключить MDA в разделе «Отладка -> Исключения» в разделе «Помощники по управляемой отладке», но каждый раз, когда вы сбрасываете эти параметры, проклятый MDA снова включается)

...