Запретить элемент управления MFC ActiveX использовать библиотеки DLL, которые уже загружены в процесс - PullRequest
0 голосов
/ 04 марта 2011

Короткая версия : каким образом элемент управления MFC ActiveX, загружаемый на веб-страницу Internet Explorer, гарантирует, что связанные с ним библиотеки DLL загружаются из своего собственного каталога, а не выбирает библиотеки с одинаковыми именами, которые уже могут быть загружен в процесс?

Длинная версия, с кровавыми подробностями : У меня есть приложение myapp.exe, которое использует набор DLL: one.dll, two.dll и three.dll.

Те же библиотеки DLL также используются элементом управления MFC ActiveX, который предоставляет некоторые из тех же функций, что и myapp.exe, поэтому есть mycontrol.ocx, который также связывается с этими библиотеками DLL. Элемент управления ActiveX связан с типом application/myapp MIME, поэтому IE будет использовать его для отображения документов, созданных с помощью myapp.exe.

Возможно установить обе версии 1 и 2 myapp.exe, но только самая последняя версия mycontrol.ocx (версия 2) связана с типом application/myapp MIME:

c:\Program Files\MyApp\Version 1\
                                 myapp.exe
                                 mycontrol.ocx
                                 one.dll
                                 two.dll
                                 three.dll
c:\Program Files\MyApp\Version 2\
                                 myapp.exe
                                 mycontrol.ocx  <-- registered with the MIME type
                                 one.dll
                                 two.dll
                                 three.dll

Вот где это сложно: myapp.exe имеет встроенный элемент управления Internet Explorer для отображения веб-контента. Вы можете запустить версию 1 myapp.exe, указав, что встроенный Internet Explorer на документ application/myapp, и IE загрузит версию 2 mycontrol.ocx, чтобы просмотреть его. Это должно быть хорошо, но это не так:

В результате Windows загружает mycontrol.ocx, видит, что она зависит от one.dll и что в процессе уже есть one.dll, и указывает таблицу импорта mycontrol.ocx на уже загруженную ( версия 1) one.dll, а не загрузка версии 2 из one.dll. Это терпит неудачу, потому что версия 2 mycontrol.ocx использует новые API в версии 2 one.dll, которых не было в версии 1.

Как мне прекратить это делать? Если one.dll еще не загружен, Windows будет искать его в c:\Program Files\MyApp\Version 2, и все будет хорошо. (И я не могу переименовать все свои модули для каждой версии программного обеспечения!)

Неудачное решение # 1 : я дал mycontrol.ocx манифест, который задает <file ...> элементов для всех библиотек DLL, но это не работает. one.dll загружается из каталога Version 2, а two.dll - нет. Я предполагаю, что это потому, что two.dll загружается в результате one.dll ссылки на него, а one.dll не имеет такого манифеста.

Неудачное решение # 2 : Итак, я добавил манифест к всем библиотекам DLL, каждая из которых перечисляет свои зависимости в <file ...> элементах. Но это полностью сломало myapp.exe, потому что MFC теперь обрабатывает каждую DLL как имеющую собственный контекст активации, и это неправильно - должен быть один контекст MFC для всего процесса (в случае myapp.exe) или всего экземпляра контроль (в случае mycontrol.exe). У меня не может быть нового контекста активации для каждого модуля; Мне нужен один для всего mycontrol.ocx и связанных с ним DLL.

Я изменил все манифесты, чтобы использовать один и тот же атрибут name=, в надежде, что это поместит их всех в один и тот же контекст, но это никак не отразилось.

Неудачное решение # 3 : Я дал myapp.exe манифест с надписью <file name="mycontrol.ocx"/> в надежде заставить версию 1 приложения использовать версию 1 элемента управления, что было бы хорошо. Но это не удается, потому что когда Internet Explorer загружает mycontrol.ocx, он вызывает LoadLibrary с полным путем к версии 2 mycontrol.ocx, и перенаправление манифеста не работает, когда модули загружаются с использованием полного пути.

Что-то, что я не могу сделать : Я не могу изменить код, который загружает элемент управления, потому что это делает Internet Explorer (через тип MIME).

Любые решения, предложения или простые сообщения сочувствия будут с благодарностью приняты.

Ответы [ 3 ]

1 голос
/ 04 марта 2011

Один из вариантов - попытаться указать зависимости DLL OCX от загруженной задержки, а затем написать свою собственную вспомогательную функцию с задержкой загрузки, которая использовала LoadLibraryEx (), чтобы быть уверенной в загрузке библиотек DLL из пути, который вы хотите использовать.Я экспериментировал с этим в прошлом и заставил его работать с исполняемым файлом, но я не понимаю, почему он не будет работать с OCX.

MSDN имеет приличную документацию по с использованием задержкивспомогательная функция загрузки .В вспомогательной функции отложенной загрузки вы хотите сконцентрироваться на случае "dliNotePreLoadLibrary" и вернуть HMODULE правильной DLL, которую вы получили с LoadLibraryEx ().

Кстати, в конце концов, я неНе используйте этот подход: я просто убедился, что все библиотеки DLL имеют номер версии в них.В конце концов, это самый простой способ ...

0 голосов
/ 07 апреля 2011

Вот как я решил это в конце:

Я разделил mycontrol.ocx на две части, mycontrol.dll, который реализует функциональность, и минимальный mycontrol.ocx, который реализуетлогика регистрации и действует как прокладка к реальному модулю.Шим mycontrol.ocx не имеет зависимостей DLL.Вот что он делает:

  • Если рядом с исполняемым файлом, запустившим процесс, есть mycontrol.dll, это должна быть новая версия myapp.exe, и программа-шимм загружает mycontrol.dllи отражает DllGetClassObject и DllCanUnloadNow вызовы к нему.

  • Если рядом с исполняемым файлом есть mycontrol.ocx, но нет mycontrol.dll, это должна быть старая версия myapp.exe, поэтому шим загружает mycontrol.ocx и перенаправляет на него.

  • Если ни один из модулей не существует, это должен быть веб-браузер или какой-либо другой хост ActiveX, поэтому шим загружаетсяmycontrol.dll находится в том же каталоге, что и сам, и перенаправляет на него.

Это немного сложнее, чем в реальной жизни, но в результате все загружают код, который ониожидали загрузки, и все это работает.

0 голосов
/ 05 марта 2011

Зная немного об аде DLL, я ничего не знаю о "MFC Activation Context". Вот почему ваша идея №2 выше кажется твердой.

Но если это не сработает, я бы попробовал исследовать три возможных решения:

  1. Безумная идея. Когда вы регистрируете "mycontrol.ocx" в реестре как связанный с application / myapp, вы в настоящее время регистрируете его по полному пути (c: \ program files \ app \ version2 \ mycontrol.ocx "). Просто зарегистрируйте его как" mycontrol.ocx "без указания каталога. Если вам повезет, элемент управления IE будет" LoadLibrary ("mycontrol.ocx") и найдет его в том же каталоге, что и ваш EXE. Это, конечно, ломается, если вам действительно нужен mycontrol.ocx для загрузки в автономном экземпляре IE. Но, возможно, вы могли бы иметь альтернативный тип MIME (или comid) для внешних страниц, чтобы загрузить элемент управления напрямую.

  2. При установке вашего приложения поместите EXE-файл в другой каталог, чем DLL. Затем используйте раздел реестра "AppPath" , чтобы виртуально добавить конкретный каталог DLL к пути приложения. Единственная проблема заключается в том, что я не думаю, что вы можете установить имя ключа AppPath с полным путем. Но я знаю, что у вас может быть имя EXE с полным путем к файлу с другим именем. Таким образом, мы можем «виртуально переименовать» второй экземпляр «myapp.exe» в «myapp2.exe». В ярлыках на рабочем столе и в пунктах меню «Пуск» все они запускают «myapp2.exe», но он перенаправляется на «version2 \ app \ myapp.exe»

    c:\Program Files\MyApp\Version 1\app\
                                          myapp.exe
    c:\program files\MyApp\Version 1\dll\
                                          mycontrol.ocx
                                          one.dll
                                          two.dll
                                          three.dll
    
    HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\myapp.exe
          (default)=c:\program files\MyApp\Version1\app\myapp.exe (type == REG_EXPAND_SZ)
          Path=c:\program files\MyApp\Version1\dll;c:\program files\MyApp\Version1\app;
    
    
    
    c:\program files\MyApp\Version 2\app\
                                         myapp.exe
    c:\program files\MyApp\Version 2\dll\
                                          mycontrol.ocx
                                          one.dll
                                          two.dll
                                          three.dll
    
    
    // NOTICE THE VIRTUAL RENAME TO MYAPP2 in the line below
    HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\myapp2.exe 
          (default)=c:\program files\MyApp\Version 2\app\myapp.exe (type == REG_EXPAND_SZ)
          Path=c:\program files\MyApp\Version 2\dll;c:\program files\MyApp\Version 2\app;
    
  3. Используйте Установка Windows Side by Side и соответствующие манифесты в ваших EXE-файлах и DLLS.

...