Загрузите 2 версии одной и той же DLL в одном процессе - PullRequest
8 голосов
/ 16 февраля 2011

Я хочу сделать именно то, что описано здесь , но принятое решение не работает для меня.Я предполагаю, что причина объяснена здесь :

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

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

Я хочу, чтобы мое приложение имело следующую структуру.

c:\Exe
 |
 |----- c:\DLL\DLL.dll, c:\DLL\common.dll 
 |
 |----- c:\DLL2\DLL2.dll, c:\DLL2\common.dll

Мой EXE-файл загрузит библиотеки DLL через

LoadLibrary("c:\\DLL\\DLL.dll");
LoadLibraryEx("c:\\DLL2\\DLL2.dll");

common загружается неявно в обоих случаях.

Я попробовал опцию SetDllDirectory, но всегда загружен только один common.dll.

Я добавил информацию о версии в common.dll.c: \ DLL \ common.dll имеет версию 2.0.1.0, а c: \ DLL2 \ DLL2.dll имеет версию 4.0.1.0

. Я вставил следующий манифест с соответствующей информацией о версии, но это не помогло.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="common" version="4.0.1.0" processorArchitecture="x86"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>

Есть ли решение этой проблемы?

1 Ответ

6 голосов
/ 16 февраля 2011

Где вы вложили манифест? EXE или DLL?

У вас есть два основных способа сделать это, оба включают превращение «общего» в частную сборку SxS путем создания манифеста для него.

Тогда:

  1. Если DLL и DLL2 содержат манифесты, перечисляющие зависимые сборки, вам нужно добавить зависимую сборку к их манифестам, указав «acme.common» (например) в качестве зависимой сборки. Поскольку зависимые сборки всегда ищутся, по умолчанию в папке загружаемых модулей, каждая DLL будет загружать свою собственную локальную копию общих.

  2. Если вы просто полагаетесь на контекст активации приложений по умолчанию для выполнения большей части тяжелой работы, то вы можете попробовать использовать ActivationContext API. Вызовите CreateActCtx дважды, указав две две разные папки в качестве базовой папки для результирующего контекста.

В псевдокоде:

HACTCTX h1 = CreateActCtx( ... for DLL ... );
HACTCTX h2 = CreateActCtx( ... for DLL2 ...);

ActivateActCtx(h1,...);
LoadLibrary("C:\\DLL\\DLL1.DLL");
DeactivateActCtx();
ActivateActCtx(h2,...);
LoadLibrary("C:\\DLL2\\DLL2.DLL");
DeactivateActCtx...

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


Для реализации варианта 1: Во-первых, я не рекомендую пытаться использовать имя dll в качестве имени сборки. Итак, создайте манифест, который выглядит так в каждой папке:

<!-- acme.common.manifest -->
<assembly manifestVersion="1.0">
    <assemblyIdentity type="Win32" name="acme.common" version="1.0.0.0" processorArchitecture="x86"/>
    <file name="common.dll"/>
</assembly>

Вы можете исправить номер версии, чтобы он соответствовал версии common.dll в каждой папке, но это не важно.

Затем, либо список манифеста, который вы перечисляете, или директива, подобная этой, если вы используете Visual Studio

#pragma comment(linker, "/manifestdependency:\"acme.common'"\
                   " processorArchitecture='*' version='1.0.0.0' type='win32'\"")

Просто убедитесь, что версии зависимых сборок соответствуют версиям соответствующей сборки acme.common.

...