Como evito o bloqueio do carregador?
-
21-09-2019 - |
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:
- http://social.msdn.microsoft.com/forums/en-us/vsto/thread/dd192d7e-ce92-49ce-beef-3816c88e5a86
- http://msdn.microsoft.com/en-us/library/aa290048%28vs.71%29.aspx
- http://forums.devx.com/showthread.php?t=53529
- 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
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)