Pergunta

Temos um aplicativo gerenciado, que usa uma montagem. Essa montagem usa algum código C ++ não gerenciado.

O código C ++ gerenciado está em uma DLL, que depende de várias outras DLLs. Todas essas DLLs são carregadas por este código. (Carregamos todas as DLLs que o ImageCore.dll depende primeiro, para que possamos dizer quais estão faltando, caso contrário, ele apareceria como ImageCore.dll falhou ao carregar, e o arquivo de log não daria pistas sobre o porquê).

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");
        }
    }
}

E este código é chamado por

public class ImageDoc : IDisposable {
    static ImageDoc()
    {
        ImageHawk.ImageCore.Utility.Interop.PreloadAssemblies();
    }
    ...
}

Que é o construtor estático.

O mais próximo possível, assim que tentarmos usar um objeto IMAGEDOC, a DLL que contém essa montagem é carregada e, como parte dessa carga, o construtor estático é chamado, o que, por sua vez, faz com que várias outras DLLs sejam carregadas como Nós vamos. O que estou tentando descobrir é como adiamos o carregamento dessas DLLs, para que não executemos o Smack Dab nessa trava do carregador que está sendo expulsa por causa do construtor estático.

Eu juntei muito olhando para:

  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

Mas não consigo encontrar uma maneira de fazer com que essas DLLs externas sejam carregadas sem que isso aconteça no ponto em que a classe está carregando. Eu acho que preciso obter essas chamadas de biblioteca de carga do construtor estático, mas não sei como chamá -las antes que sejam necessárias (exceto como isso é feito aqui). Eu preferiria não precisar colocar esse tipo de conhecimento das DLLs em todos os aplicativos que usam essa montagem. (E não tenho certeza se isso resolveria o problema ....

O estranho é que a exceção parece estar acontecendo apenas enquanto corre dentro do depurador, não enquanto fica fora do depurador.

Como posso carregar essas DLLs sem entrar em conflito:

LoadLibrary <- .NET loads the class from assembly dll 
DllMain 
LoadLibrary <- -Due to Static ctor 
DllMain
Foi útil?

Solução

Loaderlock é um MDA (Assistente de depuração Gerenciado) aviso do depurador. Diz que lá poderia Seja um problema com o código. Isso só acontece ao correr sob o depurador, porque é o depurador que está fazendo o MDA verifica para informar que, em algumas circunstâncias, um impasse "poderia ocorrer".

Infelizmente, não posso ajudá -lo muito além disso. Minha experiência de carregador é que (a) é um aviso misterioso que o VS dá a você, mas há um pequeno apoio precioso dizendo o que realmente fazer para resolvê -lo e (b) nosso aplicativo está sendo executado há 4 anos com um carregador Sair (no DirectX, por isso nem está no nosso código) e nunca causou um problema, além de ser um aborrecimento irritante toda vez que corremos sob o depurador. YMMV, é claro.

(Você pode desativar o MDA em depuração -> Exceções na seção de assistentes de depuração gerenciada, mas toda vez que você redefine essas configurações, o maldito MDA liga novamente)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top