2012-01-26 11 views
11

Estoy intentando descargar una DLL de terceros que funciona mal de mi proceso .NET, ya que parece estar causando un problema que siempre se resuelve al reiniciar mi aplicación. En lugar de reiniciar la aplicación, me gustaría eliminar y volver a cargar la DLL.Descargue forzosamente DLL del ensamblado

La DLL se carga utilizando LoadLibrary y se elimina utilizando FreeLibrary (utilizando DllImport s tomada del sitio web de P/Invoke). Cuando llamo al LoadLibrary() veo que la DLL aparece en la lista de DLL en Process Explorer, y cuando llamo al FreeLibrary() veo que la DLL desaparece de la lista de DLL, como se esperaba.

Sin embargo, una vez que he llamado la función Initialize() de la biblioteca de terceros, FreeLibrary() ya no elimina el archivo DLL de la lista, incluso si yo llamo un Deinit() método correspondiente de antemano. Llamar a otra función en la biblioteca no tiene este problema. Sin embargo, debo Initialise() la biblioteca antes de usar!

He intentado aislar la DLL creándola en su propia AppDomain, y luego descargo este dominio después de liberar la DLL.

No me sale códigos de retorno de error o excepciones de Initialize() o Deinit(), desde el LoadLibrary() o FreeLibrary() o de crear o descargar la AppDomain.

que utiliza el código siguiente para crear el AppDomain e inicializar:

string pathToDll = Assembly.GetExecutingAssembly().CodeBase; 
m_Domain = AppDomain.CreateDomain("MyAppDomain", null, new AppDomainSetup { PrivateBinPath = pathToDll }); 
m_Module = (ThirdPartyModule)m_Domain.CreateInstanceFromAndUnwrap(pathToDll, typeof(ThirdPartyModule).FullName); 
m_Module.Init(); 

Para deinitialise y descargar el AppDomain:

m_Module.Free(); 
m_Module = null; 
if (m_Domain != null) 
{ 
    AppDomain.Unload(m_Domain); 
    m_Domain = null; 
} 

Por último, mi ThirdPartyModule clase de montaje:

internal class ThirdPartyModule : MarshalByRefObject 
{ 
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    internal static extern IntPtr LoadLibrary(string lpFileName); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern bool FreeLibrary(IntPtr hModule); 

    public IntPtr Module { get; set; } 

    public ThirdPartyModule() 
    { 
     Module = LoadLibrary("Misbehaving.dll"); 
    } 

    public void Free() 
    { 
     FreeLibrary(Module); 
     Module = IntPtr.Zero; 
    } 

    // ... 
} 

Parece que debería comportarse como ¿Esperaba? Si no, ¿hay alguna otra forma en que pueda garantizar que este archivo DLL esté completamente descargado?

Edición: Más información

  • El DLL contiene el código nativo, probablemente compilado de C/C++
  • Desafortunadamente mi proceso está limitado al uso de .NET 2 solamente (por lo que no hay solución WCF).
  • Estoy usando WinXP Pro x64 SP2 pero la solución debe ser compatible con XP, Win7 x32/x64, etc.
  • La DLL se utiliza para comunicarse con un token USB
+0

es la DLL una DLL nativa? – Yahia

+4

Podría ejecutar el archivo DLL en otro proceso y comunicarse con él a través de WCF. Puedes simplemente matar todo el proceso cuando quieras descargarlo. – CodingBarfield

+0

@Yahia: sí, creo que es una DLL C/C++. –

Respuesta

4

recomendaría para implementar un proceso separado (EXE) el cual su aplicación se inicia y que a su vez carga el archivo DLL.

Esto le permite matar el proceso cada vez que sea necesario ...

Veo varias opciones sobre la forma de comunicarse - por ejemplo:

  • usted podría utilizar COM (si se implementa como un servidor COM fuera de proceso)
  • podría utilizar memoria compartida (rendimiento muy alto, ver this para un tutorial y this para un envoltorio NET 2)

Dado que usted escribe que el método debe ser compatible con varias versiones de Windows y algunos vienen con un cortafuegos de escritorio me abstenga lado a otro Estoy usando cualquier cosa "de red" para el IPC.

Cuestiones relacionadas