Как правильно выгрузить DLL расширения C++ Shell

У меня есть dll расширения оболочки, написанная на C++ и COM. DLL зарегистрирована и загружена в память. Моя программа установки обновления сделает следующее:

  • Отмените регистрацию dll расширения оболочки, уничтожьте explorer.exe
  • Скопируйте более позднюю версию dll расширения оболочки (Шаг 2)
  • Запустите explorer.exe

Это работает нормально. Но проблема в следующем:

Если пользователь открыл какие-либо другие приложения (Internet Explorer, иногда диспетчер задач Windows, блокнот и т. д.), шаг Шаг 2 не выполняется.

Есть ли способ закрыть все хуки dll расширения оболочки при обновлении dll.

В dll я использую GetOverlayInfo, контекстное меню, подключение к базе данных и т.д.


person JChan    schedule 06.07.2012    source источник
comment
Ошибочно думать, что убийство explorer.exe чем-то поможет. Во-первых, это очень агрессивная процедура (установщик Windows вместо этого переместит используемый файл в другое место на том же томе, чтобы установить новый файл в исходное место), а во-вторых, он не может работать вообще, потому что пользователь может использовать совершенно другой файловый менеджер, использующий расширения оболочки. Я делаю это сам, и установщики, делающие такие предположения, просто раздражают. Вы можете удаленно закрывать ссылки, вызывая все виды хаоса. Не делай этого!   -  person 0xC0000022L    schedule 06.07.2012
comment
Я с @0xC0000022L. Я ненавижу перезапуски, как и все остальные, но я думаю, что это требует одного. Вы можете завершить установку при повторном запуске системы, до запуска проводника.   -  person eran    schedule 06.07.2012
comment
@eran: на самом деле требуется только перезапуск затронутых приложений (или выход из системы).   -  person 0xC0000022L    schedule 06.07.2012
comment
Ваша DLL-расширение оболочки загружается в другие процессы через диалоговые окна оболочки. Как Файл + Открыть в Блокноте. Вы можете переименовать исходную DLL и поместить новую, но для того, чтобы она вступила в силу, необходимо выйти из системы.   -  person Hans Passant    schedule 06.07.2012
comment
@HansPassant: просто интересно, знаете ли вы окончательный ответ на этот вопрос: будет ли новое расширение оболочки использоваться новыми экземплярами приложений сразу или нет? Я не уверен на 100%.   -  person 0xC0000022L    schedule 06.07.2012
comment
Спасибо всем за ваши ценные предложения. Позвольте мне проверить, какое из приведенных выше решений лучше всего подходит для моей проблемы.   -  person JChan    schedule 06.07.2012


Ответы (2)


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

Большинство людей, кажется, до сих пор не знают, что MoveFileMoveFileEx) можно использовать для перемещения DLL или EXE-файлов, которые в настоящее время используются запущенным приложением.

Это подход, который использует установщик Windows. Вы когда-нибудь замечали папку \Config.msi в корне данного диска после установки какого-нибудь .msi? Эта папка на самом деле содержит (перемещенные и обычно переименованные в какое-то уникальное «временное» имя) исходные файлы, которые были перемещены, но все еще использовались в то время. Затем они обычно планируются для удаления при загрузке (MoveFileEx с MOVEFILE_DELAY_UNTIL_REBOOT).

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

(*) Я не уверен в этом на 100% из-за правил, которые применяются к загрузке DLL и запрещают повторную загрузку модулей с тем же именем при некоторых обстоятельствах.

person 0xC0000022L    schedule 06.07.2012
comment
Мы используем установщик битрок. Я попробую ваше предложение. - person JChan; 06.07.2012
comment
Если есть блокировка DLL, установщик Bitrock скопирует новый файл, добавив несколько уникальных номеров. Но пользователь должен перезагрузить систему. Во время перезагрузки он удалит старую dll, а также удалит уникальные номера из dll. - person JChan; 07.07.2012
comment
@JChan: похоже, они используют технику, которую использует установщик Windows и которую я описал. - person 0xC0000022L; 09.07.2012
comment
Решение не является надежным, т.е. в процессе обновления мы отменяем регистрацию старой dll, копируем новую dll и регистрируем ее. Если произошла блокировка dll, она никогда не зарегистрирует новую dll. но он заменит старую dll новой. Это проблема. Новую dll необходимо зарегистрировать. Мне интересно, как я могу решить эту проблему - person JChan; 09.07.2012
comment
@JChan: если вы имеете в виду самостоятельную регистрацию, вам следует вообще прекратить это делать. Есть причина, по которой MS не рекомендует использовать это для своей собственной технологии (установщик Windows). Вместо этого установите значения реестра самостоятельно. Кроме того, во время обновления регистрация и отмена регистрации будут необходимы лишь в редких случаях, потому что большинство значений, вероятно, являются общими для двух версий DLL. - person 0xC0000022L; 10.07.2012
comment
@oxC0000022L - спасибо за помощь - person JChan; 11.07.2012

В зависимости от вашего установщика вы можете использовать Диспетчер перезапуска поддерживается в Windows Vista+. Это позволит вашей установке запрашивать каждое приложение, использующее вашу DLL, и пытаться изящно закрыть их. Если их не может быть, то вам нужно будет прописать его для замены при перезагрузке. После завершения установки Restart Manager попытается перезапустить все закрытые им программы (которые поддерживают перезапуск).

person Deanna    schedule 13.03.2013