2008-11-24 11 views
11

Estoy utilizando dos bibliotecas comerciales que son producidas por el mismo proveedor, llamadas VendorLibA y VendorLibB. Las bibliotecas se distribuyen como muchas DLL que dependen de la versión del compilador (por ejemplo, VC7, VC8). Ambas bibliotecas dependen de otra biblioteca, producida por este proveedor, llamada VendorLibUtils y contenida en una DLL.¿Puedo usar dos versiones incompatibles de la misma DLL en el mismo proceso?

El problema: VendorLibA utiliza una versión diferente de VendorLibUtils que VendorLibB. Las dos versiones no son compatibles con binarios, e incluso si lo fueran, sería una mala idea usar una versión incorrecta.

¿Hay alguna manera de que pueda usar las dos bibliotecas en el mismo proceso?

Nota: LoadLibrary no puede resolver esto ya que mi proceso no es el que está importando VendorLibUtils.

EDIT: olvidó de mencionar lo obvio, no tengo a código fuente de cualquiera de las bibliotecas comerciales y probablemente nunca tendré ( suspiro).

EDIT: La alternativa por cierto, es de hacer esto: How to combine GUI applications in Windows

+0

Wow. Suena como una mala situación por todos lados. Cuelga ahí. – ahockley

Respuesta

3

Como no está utilizando directamente VendorLibUtils, supongo que no se puede utilizar LoadLibrary etc.

Si los VendorLibUtils DLL sólo se tienen las exportaciones por ordinal, que probablemente podría cambiar el nombre de una de las bibliotecas y los parchear el correspondiente vendorlib X para usar un nombre de archivo diferente para sus importaciones.

Si las DLL de VendorLibUtils tienen uno o más símbolos exportados con los mismos nombres, podría parchear las tablas de importación y exportación también, pero ¡ojalá no! :-)

+0

Exportado por nombre es: /. Cualquier palabra de búsqueda de Google para esto? – kshahar

+0

Haga una aplicación de prueba y cuatro DLL que reproduzcan este escenario, para ver si puede tener el mismo nombre de símbolo en las dos DLL "TestLibUtils" y que TestLibA y TestLibB ejecutan la función correcta. –

2

No soy un experto en archivos DLL, pero la única manera que veo posible sería utilizar LoadLibrary() y cargar explícitamente las DLL. Luego puede colocar las funciones/clases, etc. en espacios de nombres separados usando GetProcAddress().

HMODULE v1 = LoadLibrary(_T("libv1_0.dll")); 
libv1_0::fun_in_lib = reinterpret_cast<FUNTYPE>(GetProcAddress(v1, _T("fun_in_lib")); 

y

HMODULE v2 = LoadLibrary(_T("libv2_0.dll")); 
libv2_0::fun_in_lib = reinterpret_cast<FUNTYPE>(GetProcAddress(v2, _T("fun_in_lib")); 

si esto iba a funcionar o no todavía tipo de depende de la biblioteca, por lo que puede o no puede trabajar, pero por lo que puedo decir que es la única posibilidad.

5

Creo que su opción más prometedora es quejarse en voz alta al vendedor que distribuye productos mutuamente incompatibles. Eso más bien va en contra de la idea de una DLL.

No puede simplemente poner las DLL en directorios diferentes. Una vez que se carga una DLL con un nombre dado, todos los demás intentos de cargar otra DLL con el mismo nombre de módulo simplemente usarán la que ya está cargada, incluso si las rutas son diferentes.

De eso, podemos concluir que para cargar dos copias de VendorLibUtils, una copia debe tener un nombre diferente. No puede simplemente cambiar el nombre del archivo DLL; el código en su programa no sabrá buscar el archivo diferente. Por lo tanto, tal vez haya una manera de editar la tabla de importación de VendorLibB para hacer que piense que las funciones que necesita están en VendorLibUtilsB.dll en lugar de solo VendorLibUtils.dll.Me temo que no conozco ninguna utilidad que pueda hacer eso, pero tengo pocas dudas de que es posible hacerlo.

2

Como mencionó otra persona, puede cambiar el nombre de una de las copias de VendorLibUtils y modificar la tabla de importación de la DLL VendorLib asociada para vincularla, en lugar de VendorLibUtils.dll con la que se creó.

Hay algunas herramientas que le permiten editar archivos EXE/DLL de esta manera. CFF Explorer es bastante bueno que permite la edición de la tabla de importación. Si abre la DLL VendorLib en ella y va a la sección Importar Directorio (en el árbol de la izquierda), verá una lista de módulos en la parte superior de la ventana principal. Puede cambiar el nombre del módulo haciendo doble clic en su nombre. Luego solo guarda la DLL y ahora debería usar su DLL VendorLibUtils renombrada.

Por supuesto, esto supone que vendorlib utiliza la tabla de importación para acceder VendorLibUtils, que puede que no - se puede utilizar LoadLibrary/GetProcAddress, en cuyo caso no verá una entrada de la tabla de importación de VendorLibUtils.

En realidad, si el vendorlib hace uso de la tabla de importación, pero también LoadLibrary utiliza para acceder a la VendorLibUtils DLL en algunos lugares (lo he visto hacer), esos lugares aún utilizan el equivocado. Si cambia el nombre de ambas bibliotecas, al menos puede ver un error si este es el caso (ya que una DLL con el nombre original no existirá ahora). Hay una manera de lidiar con esto si ocurre, pero comienza a ser bastante complicado en este punto, así que no daré más detalles a menos que realmente desee/necesite saber.

1

¿Quiere decir que tiene una situación similar a MSVCRT80.DLL y MSVCRT90.DLL? Hay una buena razón por la que Microsoft numeró estas DLL. Si ambas se llamaran MSVCRT.DLL, solo una de ellas se cargaría en un solo proceso.

+0

La situación que tengo es en la que ambas DLL se llaman MSVCRT.DLL, pero son diferentes en su contenido. – kshahar

0

En realidad, es posible cargar implícitamente diferentes versiones de un dll en un solo proceso.

Hacer esto implica:

  1. Creación de dos conjuntos, cada uno que contiene una versión de la DLL que se debe cargar varias veces. Suena complicado, pero prácticamente implica poco más que crear (2) subcarpetas con nombre, cada una con un archivo .manifest que contiene algún xml y su propia copia del dll. Entonces, VendorUtilsAssemblyV1 y VendorUtilsAssemblyV2

  2. Haciendo que cada dll dependiente utilice el mecanismo de ensamblaje para resolver la dependencia implícita, agregando una directiva assemblyDependency que identifica explícitamente VendorUtilsAssemblyV1 o V2.

Hay algunas opciones para el punto 2. Si los archivos VendorLibA y VendorLibB no contienen sus propios manifiestos, a continuación, simplemente puede añadir archivos de manifiesto con la directiva dependentAssembly requerido llamado VendorLibA.2.dll.manifest y VendorLibB .2.dll.manifest. Si ya contienen manifiestos (probablemente para vincular a VS2005 o VS2008 C-Runtime), utilice la herramienta MT.EXE para fusionarse en la nueva dependencia.

4

Tuve un problema similar. Específicamente, quería usar un PyQt de un intérprete de Python incrustado en una aplicación que estaba usando una versión incompatible de Qt. Había dos Qt DLL utilizados por la aplicación principal: QtCore.dll y QtGui.dll.

Cuando me gustaría cargar PyQt desde el intérprete de Python incrustado, me gustaría tener un error:

ImportError: DLL load failed: The specified procedure could not be found. 

Esto ocurrió en la línea:

from PyQt4 import QtGui 

El problema es que la vez un QtGui incompatibles .dll se carga en el espacio de proceso de la aplicación principal, cualquier referencia a QtGui.dll (por ejemplo, desde el archivo QtGui.pyd) es incorrecta.

Lo que sucedió a continuación, no me enorgullezco.

First I renamed QtGui4.dll in the PyQt distribution to QtGuiX.dll and then renamed the QtCore4.dll to QtCoreX.dll . Notice that the renaming maintained the same number of characters, this is important.

Next I opened the file QtGui.pyd in Notepad++, and replaced all plain-text references of QtGui4.dll to QtGuiX.dll and from QtCore4.dll to QtCoreX.dll . I repeated the process for the files: QtCore.pyd , QtGuiX.dll and QtCoreX.dll .

Finally I checked that my PyQt test application still worked. It did! Then I tried running the PyQt test application from the embedded Python interpreter, and it worked as well.

So, it seems to works in a couple of trivial cases. I expect that I need to repeat the process for all DLLs and PYDs in the PyQt distribution.

Esto probablemente no es la manera correcta de hacer las cosas, pero no puedo pensar en alguna razón concreta el modo en que podría hacer estallar (que no sea si cambio de la longitud del nombre de archivo).

Acredita (o culpa) a otros en el hilo por inspirar este terrible cuento.

+0

Hola, este es exactamente el problema que intento abordar. Tenemos una gran aplicación de C++ que incorpora un intérprete de Python (a través de la DLL de Python) para admitir los complementos de Python. Usamos Boost.Python para exponer la API de C++ a los complementos de Python y PyQt para permitir que los complementos accedan a nuestra interfaz de usuario. Sin embargo, enviamos nuestras propias DLL Qt, por lo que PyQt necesita usarlas en lugar de las suyas propias. ¿Su solución es la forma aceptada de hacer las cosas? :) ¿Conoces alguna forma más "oficial"? ¿Alguna información que no hayas compartido aquí pero que valga la pena saber? –

+0

@ FrançoisBeaune No conozco una mejor manera de hacerlo. Lo siento. – cdiggins

Cuestiones relacionadas