2008-12-18 6 views
6

Tengo un archivo DLL no administrado (el scilexer.dll del editor de código Scintilla, utilizado por Scintilla.Net desde CodePlex) que se carga desde una aplicación administrada a través del componente Scintilla.Net . La aplicación administrada por Windows se ejecuta sin problemas en entornos de 32 y 64 bits, pero necesito crear instalaciones diferentes que utilicen 64 o 32 scilexer.dll.Carga de DLL de 32 o 64 bits desde .NET código administrado

Hay una manera de distribuir ambas DLL en formato de 32 y 64 bits para que el cargador DLL de .Net Framework cargue la DLL no administrada en el formato de 32 o 64 bits dependiendo de alguna opción .config o algún "nombre de ruta" magia "cosas?

+0

yo diría que la mayoría de las veces no se molestan - a menos que usted espera que su aplicación utilice cerca de 2 GB de RAM simplemente hacer que su objetivo x86 proyecto solo, y se ejecutará en todas partes con solo la versión de 32 bits de scilexer.dll. –

Respuesta

5

P/Invoke usa LoadLibrary para cargar archivos DLL, y si ya hay una biblioteca cargada con un nombre de pila, LoadLibrary lo devolverá. Por lo tanto, si puede asignar el mismo nombre a las dos versiones de la DLL, pero ponerlas en directorios diferentes, puede hacer algo como esto solo una vez antes de su primera llamada a una función de scilexer.DLL, sin necesidad de duplicar sus declaraciones extern:

string platform = IntPtr.Size == 4 ? "x86" : "x64"; 
    string dll = installDir + @"\lib-" + platform + @"\scilexer.dll"; 
    if (LoadLibrary(dll) == IntPtr.Zero) 
     throw new IOException("Unable to load " + dll + "."); 
+0

Usó este enfoque, funcionó como un encanto. Respuesta aprobada. – massimogentilini

+0

Este pequeño truco es increíble, ¡me alegra que lo hayas publicado! En mi caso, lo usé para "precargar" un dll no administrado que estaba en la carpeta bin de mi servicio web. –

1

Puede poner el dll en system32. Los 32 bits en syswow64 y los 64 bits en el sistema real32. Para la aplicación de 32 bits, cuando tienen acceso al sistema 32, se les redirige a Syswow64.

Puede crear una entrada en el registro. La clave del software tiene una subclave llamada Wow6432Node que la aplicación de 32 bits ve como la clave del software.

Esto es lo powershell installer does.

2

El mejor que he ocurre es lo siguiente:

  • distribuyo mi aplicación con dos DLL nombrados 64 o 32
  • En el código de inicio principal son los siguientes:
  
    File.Delete(Application.StartupPath + @"\scilexer.dll"); 
    { 
     // Check for 64 bit and copy the proper scilexer dll 
     if (IntPtr.Size == 4) 
     { 
      File.Copy(Application.StartupPath + @"\scilexer32.dll", 
      Application.StartupPath + @"\scilexer.dll"); 
     } 
     else 
     { 
      File.Copy(Application.StartupPath + @"\scilexer64.dll", 
      Application.StartupPath + @"\scilexer.dll"); 
     } 
    } 
0

Las dlls no administradas se pueden instalar en el GAC lado a lado con sus contrapartes administradas. This article debe explicar cómo funciona.

4

Lamentablemente, no sé nada sobre esta DLL en particular. Sin embargo, al hacer la P/invocación usted mismo, y puede hacer frente a una pequeña duplicación, es posible crear un proxy para cada plataforma.

Por ejemplo, supongamos que usted tiene el siguiente interfaz, que debería implementarse ya sea por un 32 o 64 bits DLL:

public interface ICodec { 
    int Decode(IntPtr input, IntPtr output, long inputLength); 
} 

crear el proxy:

public class CodecX86 : ICodec { 
    private const string dllFileName = @"Codec.x86.dll"; 

    [DllImport(dllFileName)] 
    static extern int decode(IntPtr input, IntPtr output, long inputLength); 

    public int Decode(IntPtr input, IntPtr output, long inputLength) { 
     return decode(input, output, inputLength); 
    } 
} 

y

public class CodecX64 : ICodec { 
    private const string dllFileName = @"Codec.x64.dll"; 

    [DllImport(dllFileName)] 
    static extern int decode(IntPtr input, IntPtr output, long inputLength); 

    public int Decode(IntPtr input, IntPtr output, long inputLength) { 
     return decode(input, output, inputLength); 
    } 
} 

Y finalmente haga una fábrica que escoja la correcta para usted:

public class CodecFactory { 
    ICodec instance = null; 

    public ICodec GetCodec() { 
     if (instance == null) { 
      if (IntPtr.Size == 4) { 
       instance = new CodecX86(); 
      } else if (IntPtr.Size == 8) { 
       instance = new CodecX64(); 
      } else { 
       throw new NotSupportedException("Unknown platform"); 
      } 
     } 
     return instance; 
    } 
} 

Como las DLL se cargan de forma perezosa la primera vez que se invocan, en realidad esto funciona, a pesar de que cada plataforma solo puede cargar la versión que es nativa de ella. Ver this article para una explicación más detallada.

+1

¡Cuidado! He hecho exactamente lo mismo con mi aplicación, y todavía tengo problemas en sistemas de 32 bits de vez en cuando. Como no puede controlar cómo funciona el JIT, no puede estar seguro de que su aplicación no intente cargar el archivo DLL de 64 bits en sistemas de 32 bits, y viceversa. –

+0

He estado usando esto en producción durante un año y medio, y hasta ahora me ha funcionado bien. – SteinNorheim

Cuestiones relacionadas