2011-01-05 10 views
7

Tengo un programa que necesita funcionar en un entorno x86 y x64. Está utilizando los controladores ODBC de Oracle. Tengo una referencia a Oracle.DataAccess.DLL. Sin embargo, esta DLL es diferente dependiendo de si el sistema es x64 o x86.Intentando no necesitar dos soluciones separadas para el programa x86 y x64

Actualmente, tengo dos soluciones separadas y estoy manteniendo el código en ambas. Esto es atroz. Me preguntaba cuál es la solución adecuada.

Tengo mi plataforma establecida en "Cualquier CPU". y tengo entendido que VS debe compilar el archivo DLL en un lenguaje intermedio de modo que no importe si utilizo la versión x86 o x64. Sin embargo, si intento utilizar la DLL x64, recibo el error "No se pudo cargar el archivo o ensamblado" Oracle.DataAccess, Version = 2.102.3.2, Culture = neutral, PublicKeyToken = 89b483f429c47342 "o una de sus dependencias. Se realizó un intento para cargar un programa con un formato incorrecto ".

Me estoy ejecutando en una máquina de 32 bits, por lo que el mensaje de error tiene sentido, pero me deja pensando cómo se supone que debo desarrollar este programa de manera eficiente cuando necesite trabajar con x64.

Gracias.

+2

Si usted va a ser el desarrollo de una aplicación de 32/64-bit, que realmente debería estar en un sistema operativo de 64 bits. Al menos con Windows, un sistema operativo de 32 bits no puede ejecutar programas de 64 bits, pero un sistema operativo de 64 bits puede ejecutar programas de 32 bits. – rossipedia

+1

Otra pregunta para reflexionar es "¿Mi aplicación * realmente * necesita ejecutarse en 64 bits?" WOW hace un trabajo maravilloso ejecutando una aplicación de 32 bits en x64. – vcsjones

Respuesta

0

El uso de AnyCPU con enlaces iniciales nativos simplemente no va a funcionar, para eso necesita dos soluciones separadas y compilaciones como las que vio. Debe obtener un sistema de 64 bits para desarrollar o, al menos, probar x68 compilados.

Sin embargo, con la vinculación tardía, puede utilizar las propiedades de AnyCPU y del sistema para descubrir qué arquitectura está ejecutando y vincular a la dll correcta, si conserva el nombre Oracle.DataAccess.x86.dll. Si están instalados en el GAC, es aún más fácil, puede vincularse sin siquiera molestarse en probar la arquitectura primero, pero creo que todavía tiene que enlazarse tarde.

Tenga en cuenta que VMware puede ejecutar un invitado de 64 bits en un host de 32 bits, si realmente no se puede molestar en reinstalar Windows.

2

Si está ejecutando en una máquina de 32 bits, entonces tiene que cargar la versión de 32 bits de la DLL de Oracle. Un programa de 32 bits no puede hacer referencia a una DLL de 64 bits. Y un programa de 64 bits no puede hacer referencia a una DLL de 32 bits.

"Cualquier CPU" es el destino correcto si tiene múltiples versiones de la DLL externa. El truco es asegurarse de que se encuentra y carga la DLL de Oracle adecuada. Su mejor opción es ubicar la versión de 64 bits de la DLL en su sistema de 32 bits y cambiarle el nombre de modo que el tiempo de ejecución no pueda encontrarla.

+0

Creo que estamos en el mismo estadio, pero que mis pensamientos no se transmiten del todo bien. He incluido manualmente el dll de 32 bits adecuado en mi "solución de 32 bits" y el dll de 64 bits en la "solución de 64 bits". Cuando necesito generar los ejecutables construyo ambos, soluciones separadas. Cuando estoy desarrollando, solo trabajo en 32 bits, y cuando termino con los cambios en mi código, tengo que replicar esos cambios en la solución de 64 bits. Me gustaría utilizar solo una solución en lugar de dos, pero tengo los mismos resultados. –

0

Cree que puede configurar la misma solución para construir versiones x86/x64 por separado. También es posible que necesite agregar pasos posteriores a la compilación para copiar la versión correcta de la DLL a las carpetas de salida correspondientes ...

Al menos, si tiene que compilar 2 soluciones, use la misma fuente (agregue archivos como referencia a la segunda solución, no copiar en la segunda solución).

3

Esto es puramente un problema de implementación, nunca debería tener que mantener proyectos diferentes. Sin embargo, es incómodo y abuchean a Oracle por no hacerse cargo de esto ellos mismos. Otra consideración es que esta asamblea realmente debería ser ngen-ed en la máquina objetivo. Algunas opciones

  • crear dos instaladores, uno para x64 y una para x86. El cliente elige el correcto, según el sistema operativo que usa. Bastante simple, solo copia el archivo correcto.
  • Desplegar ambos conjuntos en el GAC. Ahora es automático, .NET elige el correcto en cualquier tipo de máquina.Las grandes empresas casi siempre deberían usar el GAC para poder implementar actualizaciones de seguridad, sin estar seguros de por qué Oracle no hace esto.
  • desplegar los montajes a un x86 y x64 subdirectorio del directorio de instalación. Tendrá que escribir un controlador de eventos AppDomain.AssemblyResolve que, en función del valor de IntPtr.Size, elija el directorio correcto.
  • Cambiar la plataforma de destino en su proyecto EXE para x86. Dado que su código necesita funcionar en una máquina de 32 bits, así como en una máquina de 64 bits, no hay/no debe haber una razón para construir AnyCPU.
3

Esta es una solución de trabajo para su problema:

Añadir el 2 de DLL (x86 y x64) a la solución en una subcarpeta. Hacer que se "Copiar si es más nuevo"

Referencia de la DLL correcta se utiliza para el desarrollo para la depuración de la DLL de 2 ha agregado. Hacerlo Copiar local = falso.

Lo que esto hace es que cuando se inicia la aplicación de la DLL no se carga automáticamente. No se cargará hasta que use un Tipo de ese ensamblaje. Una vez que eso suceda, se desencadenará un evento en .Net que le preguntará dónde puede encontrar su ensamblaje.

Así que en algún momento antes del primer uso de ese montaje compruebe que esté instalado a sí mismo a ese evento.

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 

En el contenido del controlador, asegúrese de cargar el archivo DLL (x86 o x64) cuando lo solicite.

static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { 
     if (args.Name.Equals("MyFullAssemblyName")) { 
      var path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); 
      if (IntPtr.Size > 4) { 
       var dll = System.IO.Path.Combine(path, @"MySubDir\MyDLL_x64.dll"); 
       return System.Reflection.Assembly.LoadFile(dll); 
      } 
      else { 
       var dll = System.IO.Path.Combine(path, @"MySubDir\MyDLL.dll"); 
       return System.Reflection.Assembly.LoadFile(dll); 
      } 
     } 
     return null; 
    } 

Voila. Ahora puede ejecutar su aplicación como 32 bits y 64 bits.

Como alternativa a la adición de los archivos DLL en una subcarpeta, puede que sean lo más recursos incrustados, y luego cargarlos como esto:

static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { 
     if (args.Name.Equals("MyFullAssemblyName")) { 
      var ass = Assembly.GetExecutingAssembly(); 

      if (IntPtr.Size > 4) { 
       var strm = ass.GetManifestResourceStream("the.resource.name.for.MyDLL_x64.dll"); 
       var data = new byte[strm.Length]; 
       strm.Read(data, 0, data.Length); 
       return Assembly.Load(data); 
      } 
      else { 
       var strm = ass.GetManifestResourceStream("the.resource.name.for.MyDLL.dll"); 
       var data = new byte[strm.Length]; 
       strm.Read(data, 0, data.Length); 
       return Assembly.Load(data); 
      } 
     } 
     return null; 
    } 

Esto no funciona para todos los conjuntos. Algunos ensambles "híbridos" tienden a fallar a menos que se carguen desde el disco (se pueden resolver escribiéndolos en el disco justo antes de cargarlos).

Cuestiones relacionadas