2008-11-24 3 views
11

Я использую две коммерческие библиотеки, которые производятся одним и тем же поставщиком, называемые VendorLibA и VendorLibB. Библиотеки распределены как много DLL, которые зависят от версии компилятора (например, VC7, VC8). Обе библиотеки зависят от другой библиотеки, созданной этим вендором, называемой VendorLibUtils и содержащейся в одной DLL.Могу ли я использовать две несовместимые версии одной и той же библиотеки DLL в одном и том же процессе?

Проблема: VendorLibA использует другую версию VendorLibUtils, чем VendorLibB. Обе версии не совместимы с двоичными файлами, и даже если бы это было, было бы плохой идеей использовать неправильную версию.

Можно ли использовать две библиотеки в одном процессе?

Примечание: LoadLibrary не может решить эту проблему, поскольку мой процесс не тот, который импортирует VendorLibUtils.

EDIT: забыл упомянуть очевидный, я не к исходному коду для любого из коммерческих библиотек, и, вероятно, никогда не будет (вздоха).

EDIT: Альтернативой Кстати, это сделать так: How to combine GUI applications in Windows

+0

Ничего себе. Похоже на плохую ситуацию. Повесить там. – ahockley 2008-11-24 20:10:23

ответ

3

Как вы не используете VendorLibUtils непосредственно, я предполагаю, что вы не можете использовать LoadLibrary и т.д.

Если VendorLibUtils DLL, только экспорт порядковыми, вероятно, можно переименовать одну из библиотек и исправить соответствующий VendorLib X, чтобы использовать другое имя файла для импорта.

Если у DLL VendorLibUtils есть один или несколько экспортированных с одинаковыми именами символов, вы должны: : нужно также исправлять импорт и экспортировать таблицы, но будем надеяться, что нет! :-)

+0

Экспортируется по имени: /. Любые слова поиска Google для этого? – kshahar 2008-11-24 21:10:59

+0

Сделайте тестовое приложение и четыре библиотеки DLL, которые воспроизводят этот сценарий, чтобы увидеть, можете ли вы иметь одинаковое имя символа в двух DLL-файлах TestLibUtils и что TestLibA и TestLibB запускают правильную функцию. – 2008-11-25 13:05:09

2

Я не эксперт в DLL, но единственный способ, которым я вижу это можно было бы использовать LoadLibrary() и явно загрузить DLL-библиотеки. Затем вы можете разместить функции/классы и т. Д. В разных пространствах имен, используя GetProcAddress().

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

и

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

ли это будет работать или нет еще вид зависит от библиотеки, так что он может или не может работать, но, насколько я могу сказать, что это единственная возможность.

5

Я думаю, что ваш самый перспективный вариант - громко жаловаться на продавца, который распространяет несовместимые друг с другом продукты. Это скорее противоречит идее DLL.

Вы не можете просто поместить DLL в разные папки. Когда DLL с заданным именем загружается, все остальные попытки загрузить другую DLL с тем же именем модуля будут просто использовать тот, который уже загружен, даже если пути разные.

Из этого можно сделать вывод, что для загрузки двух копий VendorLibUtils одна копия должна иметь другое имя. Вы не можете просто переименовать DLL-файл; код в вашей программе не будет знать, чтобы искать другой файл. Поэтому, возможно, есть способ редактировать таблицу импорта VendorLibB, чтобы заставить его думать, что функции, которые ему нужны, находятся в VendorLibUtilsB.dll, а не только VendorLibUtils.dll.Боюсь, я не знаю никакой полезности, которая сделает это, но я не сомневаюсь, что это возможно.

2

Как уже упоминалось, вы можете переименовать одну из копий VendorLibUtils и изменить таблицу импорта связанной библиотеки VendorLib для ее ссылки, а не VendorLibUtils.dll, с которой она была создана.

Есть несколько инструментов, которые позволяют редактировать файлы EXE/DLL таким образом. CFF Explorer - довольно приличный, который позволяет редактировать таблицу импорта. Если вы откроете в нем библиотеку VendorLib и перейдите в раздел «Импорт каталога» (в дереве слева), вы увидите список модулей в верхней части главного окна. Вы можете переименовать модуль, дважды щелкнув его имя. Затем вы просто сохраняете DLL, и теперь она должна использовать вашу переименованную DLL VendorLibUtils.

Конечно, это предполагает, что VendorLib использует таблицу импорта для доступа VendorLibUtils, что она не может - он может использовать LoadLibrary/GetProcAddress, в этом случае вы не увидите запись импорта таблицы для VendorLibUtils.

На самом деле, если VendorLib действительно использует таблицу импорта, но также использует LoadLibrary для доступа к VendorLibUtils DLL в некоторых местах (я видел, как это делается), эти места будут по-прежнему использовать неправильный. Если вы переименуете обе библиотеки, вы можете хотя бы увидеть ошибку, если это так (поскольку DLL с исходным именем не будет существовать сейчас). Есть способ справиться с этим, если это произойдет, но на данный момент это начинает усложняться, поэтому я не буду разбираться, если вы действительно не хотите/не должны знать.

1

Вы хотите сказать: у вас есть ситуация, аналогичная MSVCRT80.DLL и MSVCRT90.DLL? Существует хорошая причина, по которой Microsoft пронумеровала эти DLL. Если оба они назывались MSVCRT.DLL, только один из них будет загружен в один процесс.

+0

Ситуация у меня есть, где обе библиотеки DLL называются MSVCRT.DLL, но различаются по своему содержанию. – kshahar 2008-12-04 09:01:05

0

Фактически возможна неявная загрузка различных версий dll в один процесс.

Делать это влечет за собой:

  1. Создание двух узлов, каждый из которых содержит версию библиотеки DLL, которые должны быть загружены несколько раз. Звучит сложно, но практически это влечет за собой не что иное, как создание (2) названных подпапок, каждый из которых содержит файл .manifest, содержащий некоторый xml, и собственную копию dll. Так, VendorUtilsAssemblyV1 и VendorUtilsAssemblyV2

  2. Создание каждой DLL зависит использовать механизм сборки для решения неявных зависимостей - путем добавления директивы assemblyDependency, который явно идентифицирует VendorUtilsAssemblyV1 или V2.

Есть несколько вариантов для точки 2. Если файлы VendorLibA и VendorLibB не содержат свои собственные манифесты, то вы можете просто добавить файлы манифеста с требуемой директивой dependentAssembly именем VendorLibA.2.dll.manifest и VendorLibB .2.dll.manifest. Если они уже содержат манифесты (возможно, чтобы ссылаться на VS2005 или VS2008 C-Runtime), используйте инструмент MT.EXE для слияния новой зависимости.

4

У меня была аналогичная проблема. В частности, я хотел использовать PyQt из интерпретатора Python, встроенного в приложение, использующее несовместимую версию Qt. Были две Qt DLL, используемые основным приложением: QtCore.dll и QtGui.dll.

Когда я загрузил бы PyQt от переводчика встроенного Python, я получаю сообщение об ошибке:

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

Это происходило на линии:

from PyQt4 import QtGui 

Проблема заключается в том, что когда-то несовместимое QtGui .dll загружается в пространство процессов основного приложения, любые ссылки на QtGui.dll (например, из файла QtGui.pyd) неверны.

Что случилось дальше, я не горжусь.

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.

Это, вероятно, не правильный способ делать вещи, но я не могу думать о каких-либо конкретных причин, как это может взорвать (другой, чем если бы я изменить длину имени файла).

Кредит (или обвинение) другим в теме для вдохновления этой страшной сказки.

Смежные вопросы