Как мне избежать блокировки загрузчика?

StackOverflow https://stackoverflow.com/questions/2480609

  •  21-09-2019
  •  | 
  •  

Вопрос

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

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

(Вы можете отключить MDA в Debug -> Exceptions в разделе Managed Debugging Assistants, но каждый раз, когда вы сбрасываете эти настройки, проклятый MDA снова включается)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top