Добрый день, коллеги!
Меня вот какой мучает вопрос.
Каким образом можно конфигурировать и менять механизм поиска зависимых DLL модулей, прописанных в разделе импорта EXE или DLL модуля?
Поскольку в разделе импорта любого модуля указано только имя DLL, а пути нету, то загрузчику приходится самому искать ее на диске. По старинке, поиск DLL осуществляется в следующей последовательности:
Каталог, содержащий EXE-файл.
Текущий каталог процесса.
Системный каталог Windows.
Основной каталог Windows.
Каталоги, указанные в переменной окружения PATH.
Так вот ... могу ли я в этот механизм внести свои изменения/дополнения ...? Может быть с помощью манифестов ...? Ведь в манифестах прописывают инфу о том где искать CRT-шные DLL-ки, какую версию Common Controls подгружать и так далее ... Но скока я не рыл по поводу манифестов, везде инфа только о том как подключать Shared DLL типа msvcr**.dll, msvcp**.dll, atl**.dll, cmnctrls.dll, настраивать security, и так далее, а вот толкового мануала о том, что за инфу вообще можно запихать в манифест, как можно ссылаться там на сторонние DLL модули и пр., никак и нигде найти не могу ... :(
Я просто хочу чтоб все DLL приложения не располагались в одном каталоге, а были распределены по логическим подпапкам, при этом понятно связывались с EXE статически, а не динамически, существовали в единственном экземпляре каждая, не была засрана переменная Path и т.д.
Коллеги, не знаете как это можно забабахать? Можно ли это сделать с помощью манифестов?
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>Так вот ... могу ли я в этот механизм внести свои изменения/дополнения ...? Может быть с помощью манифестов ...? Ведь в манифестах прописывают инфу о том где искать CRT-шные DLL-ки, какую версию Common Controls подгружать и так далее ... Но скока я не рыл по поводу манифестов, везде инфа только о том как подключать Shared DLL типа msvcr**.dll, msvcp**.dll, atl**.dll, cmnctrls.dll, настраивать security, и так далее, а вот толкового мануала о том, что за инфу вообще можно запихать в манифест, как можно ссылаться там на сторонние DLL модули и пр., никак и нигде найти не могу ... R>Я просто хочу чтоб все DLL приложения не располагались в одном каталоге, а были распределены по логическим подпапкам, при этом понятно связывались с EXE статически, а не динамически, существовали в единственном экземпляре каждая, не была засрана переменная Path и т.д. R>Коллеги, не знаете как это можно забабахать? Можно ли это сделать с помощью манифестов?
Можно. Манифесты это только верхушка айсберга под названием isolated applications & side-by-side assemblies (не путать со сборками дотнета). Это решение прдлагается MS для уменьшения конфликтов версий, избавления от DLL-hell'а, и прочих подобных аспектов (в частности это замена механизма DLL/COM redirection).
Терминология:
Isolated application — это обычное приложение, которое 'изолировано' от возможных изменений каких-либо внешних компонентов.
Side-by-side assembly (сборка) — один файл (обычная DLL, COM-сервер, библиотека типов) или группа файлов.
* Сборка может быть установлена как private — для использования только одним приложением. Такая сборка устанавливается в папку с приложением.
* Сборка может быть установлена как shared — такие сборки хранятся в папке %windir%\WinSxS и доступны для использования любыми приложениями. Shared сборка обязательно должда быть подписанной. Private сборка также может быть подписана (но это не обязательно).
Манифесты соответственно делятся на два типа — манифесты для приложений (или компонентов) и манифесты для сборок. Манифесты первого типа описывают (в том числе) зависимости от сборок. Манифесты второго типа описывают (в том числе) содержимое сборок.
Для решения поставленной задачи нужно: собрать private сборку — сначала производится сборка всех компонентов, в нашем случае это один dll-файл (пусть будет TestDLLStatic.dll) Компилируется как обычная dll-библиотека (возможно она будет обладать своим манифестом, но это не важно).
Каждая сборка должна иметь имя, по которой ее можно идентифицировать. Этим именем так же будет названа папка, в которой хранится содержимое сборки (в MSND есть описание алгоритма поиска сборок, там учитываются и другие случаи, вроде название локали). Также нужен манифест для описания содержимого. Пусть именем будет 'MyDll', тогда манифест может иметь следующую структуру:
Т.е. список файлов (их может быть несколько), имя, версия и т.п. Подробный список разрешенных атрибутов есть в MSDN. Атрбут publicKeyToken отсутствует (это важно), т.к. сборку мы не будем подписывать.
Теперь структура папок:
TestDLLHost.exe (это приложение будет использовать нашу сборку)
MyDll - папка
|- MyDll.manifest - манифест, описанный выше
\- TestDLLStatic.dll
Название папки и файла-манифеста должны быть такими же как и атрибут 'name' используемый в манифесте.
Теперь о том как использовать эту сборку: для приложения TestDLLHost.exe должен существовать свой манифест, в котором нужно указать завивимость от нашей сборки: Такой манифест может быть внешним (отдельный файл) или внедренным. MS Visual Studio по умолчанию (правда не помню с какой версии) использует внедренный манифест — в таком случае можно воспользоваться директивой 'pragma' (в cpp файле):
Важно — требуется полное совпадение атрибутов, используемых в 'pragma' и атрибутов в сборке, т.е. type/version/processorArchitecture. Если автоматическая генерация манифестов выключена и используется внешний манифест, то в него необходимо добавать секцию dependency вручную. Все.
Hint: Файлы из MSVC CRT инсталлируются в качестве shared сборки, но ее можно превратить в private и носить с собой (release версию) — таким образом не нужно при установке проверять наличие соответствующей версии (и устанавливать в случае необходимости). Как это делается: В папку с приложением копируется папка из (например) '<X>:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86' — 'Microsoft.VC90.CRT':
После этого в файле 'Microsoft.VC90.CRT.manifest' необходимо удалить атрибут publicKeyToken. После чего на нее нужно сослаться из манифеста приложения, добавив секцию dependency/dependentAssembly (но уже без атрибута publicKeyToken).
Но нужно понимать, что если приложение будет иcпользовать другую dll и эта dll будет использовать CRT из shared сборки, то фактически в процессе окажется две копии runtim'a со всеми вытекающими последствиями.
Здравствуйте, Юрий Жмеренецкий, Вы писали: ЮЖ>Для решения поставленной задачи нужно: собрать private сборку — сначала производится сборка всех компонентов, в нашем случае это один dll-файл (пусть будет TestDLLStatic.dll) Компилируется как обычная dll-библиотека ЮЖ>/* skiped */
Ох, огромное Вам спасибо!
Вы более чем развёрнуто ответили на мой вопрос!
... а то я уже тут было начал c GetEnvironmentVariable/SetEnvironmentVariable мудрить непотреб всякий!
+ ещё подсказали как msvcp**.dll и msvcr**.dll можно с собой таскать правильным образом, а то я вечно Redistributable с собой таскаю и инсталлю, а там, как известно ещё и левые, мне не нужные, dll-ки валяются типа MFC, OpenMP, MSDIA, etc.
Спасибо большое!
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
... Допустим у меня слудующая структура приложения:
MainApp /* директория приложения */
|- MainApp.manifest /* манифест для дирректории MainApp */
|- MainApp.exe /* главный экзешник */
|- MainApp.exe.manifest /* манифест для MainApp.exe */
|- MyPlugins /* директория с плагинами */
|- |- MyPlugins.manifest /* манифест для дирректории MyPlugins */
|- |- Plugin1.dll
|- |- Plugin1.dll.manifest /* манифест для Plugin1.dll */
|- |- Plugin2.dll
|- \- Plugin2.dll.manifest /* манифест для Plugin2.dll */
|- SomeDlls /* директория с dll-ками */
|- |- SomeDlls.manifest /* манифест для дирректории SomeDlls */
|- \- Logger.dll
|- PluginManager.dll /* DLL в той же диретории, что экзешник */
\- PluginManager.dll.mainfest /* манифест для PluginManager.dll */
Т.е. рядом с экзешником лежит PluginManager.dll и две папки: MyPlugins и SomeDlls.
При этом, к примеру, MainApp.exe зависит от всех DLL в этом приложении, Plugin1.dll зависит от PluginManager.dll и Logger.dll, Plugin2.dll от Logger.dll, а PluginManager.dll — от Logger.dll.
Тогда, получается, что содержание манифестов должно быть следующим (понятно, что внешние манифесты DLL и EXE могут быть встроенными):
Всё верно?
Ничего не упустил?
В файле "MainApp.exe.manifest" не надо никак указывать зависимость на PluginManager.dll?
Ничего страшного, если все эти сборки "MainApp", "SomeDlls" и "MyPlugins" так разбросаны по подпапкам, что одни сборки ссылаются на те, которые находятся на уровень выше по файловой системе? Например как Plugin2.dll из сборки "MyPlugins" ссылается на сборку "SomeDlls", которая находится выше чем Plugin2.dll.
Во время запуска MainApp.exe, Side-by-Side загрузчик верно одуплит в каких диреториях находятся все эти сборки?
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>... Допустим у меня слудующая структура приложения: R>
R>MainApp /* директория приложения */
R> |- MainApp.manifest /* манифест для дирректории MainApp */
R> |- MainApp.exe /* главный экзешник */
R> |- MainApp.exe.manifest /* манифест для MainApp.exe */
R> |- MyPlugins /* директория с плагинами */
R> |- |- MyPlugins.manifest /* манифест для дирректории MyPlugins */
R> |- |- Plugin1.dll
R> |- |- Plugin1.dll.manifest /* манифест для Plugin1.dll */
R> |- |- Plugin2.dll
R> |- \- Plugin2.dll.manifest /* манифест для Plugin2.dll */
R> |- SomeDlls /* директория с dll-ками */
R> |- |- SomeDlls.manifest /* манифест для дирректории SomeDlls */
R> |- \- Logger.dll
R> |- PluginManager.dll /* DLL в той же диретории, что экзешник */
R> \- PluginManager.dll.mainfest /* манифест для PluginManager.dll */
R>
R>Т.е. рядом с экзешником лежит PluginManager.dll и две папки: MyPlugins и SomeDlls. R>При этом, к примеру, MainApp.exe зависит от всех DLL в этом приложении
Зависит в каком смысле?
R>Plugin1.dll зависит от PluginManager.dll и Logger.dll, Plugin2.dll от Logger.dll, а PluginManager.dll — от Logger.dll. R>Тогда, получается, что содержание манифестов должно быть следующим (понятно, что внешние манифесты DLL и EXE могут быть встроенными):
R>MainApp.manifest: R>
MainApp.exe — это не сборка, это приложение, поэтому MainApp.manifest не нужен.
R>Ничего страшного, если все эти сборки "MainApp", "SomeDlls" и "MyPlugins" так разбросаны по подпапкам, что одни сборки ссылаются на те, которые находятся на уровень выше по файловой системе? Например как Plugin2.dll из сборки "MyPlugins" ссылается на сборку "SomeDlls", которая находится выше чем Plugin2.dll. R>Во время запуска MainApp.exe, Side-by-Side загрузчик верно одуплит в каких диреториях находятся все эти сборки?
Нет, это не будет работать — кроссзагрузку через папки он не выполняет, только вниз по иерархии папок. Это утверждение справедливо в том случае, если в манифесте в секции dependentAssembly будет явно указана зависимость с именем, совпадающем с именем папки.
Но есть другой путь — можно отталкиваться от порядка инициализации контекстов активации: убрать вообще манифест для Plugin1.dll/Plugin2.dll, тогда (если я правильно понял про зависимости указанных dll's) запуск MainApp.exe приведет к загрузке PluginManager.dll [в этот момент с стеке активных контекстов будет присутствовать запись для PluginManager.dll ], а его загрузка приведет к загрузке Plugin1.dll и зависимости Plugin1.dll от PluginManager.dll будут разрешены автоматически (при отсутствии манифеста для Plugin1.dll). Зависимость Plugin2.dll от Logger.dll можно разрешить таким же способом. Зависимость PluginManager.dll от Logger.dll также, но при условии что можно гарантировать загрузку Logger.dll раньше чем PluginManager.dll.
Увы, не отвечу. Похоже ту часть, о которой идет речь добавляет WinSxS manger при установки сборки и использует для внутренних целей (вроде верификации сборки). IAssemblyName::GetProperty не распознает эту информацию.
Здравствуйте, Юрий Жмеренецкий, Вы писали: ЮЖ>PS: Имхо, logger можно и в корень вынести.
... да ситуация с Logger'ом и вообще с вышеописанным примером надуманная, чисто примера ради.
Я именно и имел ввиду, работает ли разрешение зависимостей не только сверху вниз, но и снизу вверх.
Скажем можно придумать менее надуманный пример, когда в корне будет лежать CRT-сборка, а в папке "MyPlugins" будут dll-ки, которые зависят от этой CRT, например:
MainApp /* директория приложения */
|- MainApp.exe /* главный экзешник */
|- MainApp.exe.manifest /* манифест для MainApp.exe */
|- Microsoft.VC90.CRT /* CRT-сборка */
|- |- msvcm90.dll
|- |- msvcp90.dll
|- |- msvcr90.dll
|- \- Microsoft.VC90.CRT.manifest
|- MyPlugins /* директория с плагинами */
|- |- MyPlugins.manifest /* MyPlugins-сборка */
|- |- Plugin1.dll
|- |- Plugin1.dll.manifest /* манифест для Plugin1.dll */
|- |- Plugin2.dll
|- \- Plugin2.dll.manifest /* манифест для Plugin2.dll */
|- PluginManager.dll /* DLL в той же диретории, что экзешник */
|- PluginManager.dll.mainfest /* манифест для PluginManager.dll */
|- Logger.dll /* DLL в той же диретории, что экзешник */
\- Logger.dll.mainfest /* манифест для Logger.dll.mainfest */
То есть, допустим, я решил не ставить VC++ 2008 Redistributable, а решил таскать CRT 2008-ой студии рядом с приложением, при этом MainApp.exe имеет dependencies на PluginManager.dll, Logger.dll, Plugin1.dll и Plugin2.dll, причём MainApp.exe и каждая dll-ка слинкованы с CRT 2008-ой студии динамически и соответственно имеют dependencies на msvcp90.dll и msvcr90.dll из сборки Microsoft.VC90.CRT. Это значит для каждого EXE и DLL модуля в его манифесте мне необходимо записать зависимость от Microsoft.VC90.CRT, где-то примерно так:
... и получается, что для Plugin1.dll и Plugin2.dll разрешение зависимостей от msvcp90.dll и msvcr90.dll будет проходить снизу вверх. При этом, наверное, когда SxS загрузчик разрешит зависимости MainApp.exe (при запуске приложения) и раздуплит где брать msvcp90.dll и msvcr90.dll, то Plugin1.dll и Plugin2.dll он подгрузит без проблем, т.к. ему уже будет известно месторасположение сборки Microsoft.VC90.CRT и заново её искать нет смысла.
А если представить ситуацию, что от CRT будут зависеть только Plugin1.dll и Plugin2.dll, а EXE и все остальные модули вообще не будут зависеть от CRT (не будут её использовать вообще), а Microsoft.VC90.CRT сборка будет размещена в корневой директории приложения, то при загрузке MainApp.exe, будут подгружаться Plugin1.dll и Plugin2.dll, и следовательно надо будет разрешать зависимости библиотек Plugin1.dll и Plugin2.dll именно снизу вверх. Получается так? Разрешит ли SxS загрузчик такие зависимости, если Microsoft.VC90.CRT сборка лежит рядышком с экзешником?
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, Юрий Жмеренецкий, Вы писали: ЮЖ>>PS: Имхо, logger можно и в корень вынести.
R>... да ситуация с Logger'ом и вообще с вышеописанным примером надуманная, чисто примера ради. R>Я именно и имел ввиду, работает ли разрешение зависимостей не только сверху вниз, но и снизу вверх. R>Скажем можно придумать менее надуманный пример, когда в корне будет лежать CRT-сборка, а в папке "MyPlugins" будут dll-ки, которые зависят от этой CRT, например: R>
R>MainApp /* директория приложения */
R> |- MainApp.exe /* главный экзешник */
R> |- MainApp.exe.manifest /* манифест для MainApp.exe */
R> |- Microsoft.VC90.CRT /* CRT-сборка */
R> |- |- msvcm90.dll
R> |- |- msvcp90.dll
R> |- |- msvcr90.dll
R> |- \- Microsoft.VC90.CRT.manifest
R> |- MyPlugins /* директория с плагинами */
R> |- |- MyPlugins.manifest /* MyPlugins-сборка */
R> |- |- Plugin1.dll
R> |- |- Plugin1.dll.manifest /* манифест для Plugin1.dll */
R> |- |- Plugin2.dll
R> |- \- Plugin2.dll.manifest /* манифест для Plugin2.dll */
R> |- PluginManager.dll /* DLL в той же диретории, что экзешник */
R> |- PluginManager.dll.mainfest /* манифест для PluginManager.dll */
R> |- Logger.dll /* DLL в той же диретории, что экзешник */
R> \- Logger.dll.mainfest /* манифест для Logger.dll.mainfest */
R>
R>То есть, допустим, я решил не ставить VC++ 2008 Redistributable, а решил таскать CRT 2008-ой студии рядом с приложением, при этом MainApp.exe имеет dependencies на PluginManager.dll, Logger.dll, Plugin1.dll и Plugin2.dll, причём MainApp.exe и каждая dll-ка слинкованы с CRT 2008-ой студии динамически и соответственно имеют dependencies на msvcp90.dll и msvcr90.dll из сборки Microsoft.VC90.CRT. Это значит для каждого EXE и DLL модуля в его манифесте мне необходимо записать зависимость от Microsoft.VC90.CRT, где-то примерно так: R>
Это не будет работать. Если
1) в манифесте для dll присутствует ссылка на 'Microsoft.VC90.CRT'
2) и рядом (в той же папке) с этой dll нет папки 'Microsoft.VC90.CRT' с соответствующим содержимым, то такая dll не загрузится (т.е. попытка загрузки закончится ошибкой).
Это поведение невозможно изменить даже с помощью ручного управления контекстами активации.
R>... и получается, что для Plugin1.dll и Plugin2.dll разрешение зависимостей от msvcp90.dll и msvcr90.dll будет проходить снизу вверх.
Зависимости всегда разрешаются в порядке загрузки (или вызова некоторых функций). Сначала запускается MainApp.exe — это приводит к поиску зависимостей, перечисленных в MainApp.exe.manifest (и только в нем). Загрузка каждого файла будет сопровождаться сменой активного контекста активации. При загрузке зависимой dll сначала будет произведена попытка загрузить ее зависимости, и при наличии манифеста (точнее ссылки в нем) необнаружение зависимой сборки приведет к ошибке. Но если манифест отсутствует (или в нем отсутствует соответствующая ссылка) то поиск будет продолжен в активном контексте.
R>При этом, наверное, когда SxS загрузчик разрешит зависимости MainApp.exe (при запуске приложения) и раздуплит где брать msvcp90.dll и msvcr90.dll, то Plugin1.dll и Plugin2.dll он подгрузит без проблем, т.к. ему уже будет известно месторасположение сборки Microsoft.VC90.CRT и заново её искать нет смысла.
Это верно только в частном случае (см. выше).
R>А если представить ситуацию, что от CRT будут зависеть только Plugin1.dll и Plugin2.dll, а EXE и все остальные модули вообще не будут зависеть от CRT (не будут её использовать вообще), а Microsoft.VC90.CRT сборка будет размещена в корневой директории приложения, то при загрузке MainApp.exe, будут подгружаться Plugin1.dll и Plugin2.dll, и следовательно надо будет разрешать зависимости библиотек Plugin1.dll и Plugin2.dll именно снизу вверх. Получается так? Разрешит ли SxS загрузчик такие зависимости, если Microsoft.VC90.CRT сборка лежит рядышком с экзешником?
Нет, т.к. для Plugin1.dll и Plugin2.dll указание зависимости от private сборок в манифесте эквивалентно — "искать только в той папке, где находится сама dll" (даже если MainApp.exe будет зависеть от CRT, и на момент загрузки Plugin1.dll CRT будет загружена).
Поэтому, чтобы разрулить ситуацию с CRT в корневой папке и нескольких (использующих ее) dll в подпапках — нужно добавить зависимость от CRT только для корневого модуля (обычно exe).
Здравствуйте, Юрий Жмеренецкий, Вы писали: ЮЖ>Зависимости всегда разрешаются в порядке загрузки (или вызова некоторых функций). Сначала запускается MainApp.exe — это приводит к поиску зависимостей, перечисленных в MainApp.exe.manifest (и только в нем). Загрузка каждого файла будет сопровождаться сменой активного контекста активации. При загрузке зависимой dll сначала будет произведена попытка загрузить ее зависимости, и при наличии манифеста (точнее ссылки в нем) необнаружение зависимой сборки приведет к ошибке. Но если манифест отсутствует (или в нем отсутствует соответствующая ссылка) то поиск будет продолжен в активном контексте.
То есть, поиск будет продолжен в контексте загрузки MainApp.exe. Так?
ЮЖ>Поэтому, чтобы разрулить ситуацию с CRT в корневой папке и нескольких (использующих ее) dll в подпапках — нужно добавить зависимость от CRT только для корневого модуля (обычно exe).
Ясно, т.е. чтобы приложение нормально работало в вышеописанной ситуации достаточно указать зависимость на сборку Microsoft.VC90.CRT только в манифесте приложения MainApp.exe, а все остальные DLL-ки зависящие от Microsoft.VC90.CRT (в том числе и в подпапках), загрузятся без проблем, вернее отсутствие специальной записи о ссылке на Microsoft.VC90.CRT в манифестах DLL-ек, а также тот факт, что msvcr90.dll уже спрецирована на адресное пространство процесса приведут к решению, что msvcr90.dll уже есть и её искать и грузить не надо.
Спасибо большое! Вы освободили мой затуманенный разум!
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Юрий Жмеренецкий, Вы писали: ЮЖ>Hint: Файлы из MSVC CRT инсталлируются в качестве shared сборки, но ее можно превратить в private и носить с собой (release версию) — таким образом не нужно при установке проверять наличие соответствующей версии (и устанавливать в случае необходимости). Как это делается: В папку с приложением копируется папка из (например) '<X>:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86' — 'Microsoft.VC90.CRT': ЮЖ>После этого в файле 'Microsoft.VC90.CRT.manifest' необходимо удалить атрибут publicKeyToken. После чего на нее нужно сослаться из манифеста приложения, добавив секцию dependency/dependentAssembly (но уже без атрибута publicKeyToken).
Насчёт того, чтобы таскать CRT, ATL и другие части redist'а с собой ...
Один коллега в сообщении "Side-by-side assemblies и их проблемы" своём журнале указал на файлик redist.txt, который располагается в корне инсталляции Visual Studio, например "%PROGRAMFILES%\Microsoft Visual Studio 8\redist.txt" или "%PROGRAMFILES%\Microsoft Visual Studio 9.0\redist.txt".
Кроме прочего, в этом файле написано:
Visual C++ Runtime files
Subject to the license terms for the software, you may redistribute the .EXE files (unmodified) listed below.
These files can be run as prerequisites during installation.
For your convenience, we have provided the following folders for use when redistributing VC++ runtime files. Subject to the license terms for the software, you may redistribute the folder (unmodified) in the application local folder as a sub-folder with no change to the folder name. You may also redistribute all the files (*.dll and *.manifest) within a folder, listed below the folder for your convenience, as an entire set.
Ключевое слово "unmodified".
То есть получается, что "удалить атрибут publicKeyToken" — не есть правомерно. А это значит, что сделать PRIVATE сборку из Microsoft.VC90.CRT легально нельзя!
Я прав?
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>For your convenience, we have provided the following folders for use when redistributing VC++ runtime files. Subject to the license terms for the software, you may redistribute the folder (unmodified) in the application local folder as a sub-folder with no change to the folder name. You may also redistribute all the files (*.dll and *.manifest) within a folder, listed below the folder for your convenience, as an entire set.
R>Ключевое слово "unmodified". R>То есть получается, что "удалить атрибут publicKeyToken" — не есть правомерно. А это значит, что сделать PRIVATE сборку из Microsoft.VC90.CRT легально нельзя! R>Я прав?
Ну эти товарищи, конечно, мне по жопе не постучат, если я сделаю из Microsoft.VC90.CRT приватную сборку. Но, например, имхо, зарегистрировать такой софт в Windows Vista Compatibility Center вряд ли получится ...
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
P.S. ... кстати ни в статье, ни в профиле Martin'a Richter'a я не нашёл места где бы встретилось словосочетание MS MVP, только MVP отдельно без MS ... Видимо всё-таки этот чел не из мелкософта ...
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
[...]
R>То есть получается, что "удалить атрибут publicKeyToken" — не есть правомерно. А это значит, что сделать PRIVATE сборку из Microsoft.VC90.CRT легально нельзя! R>Я прав?
Прав, нужно смотреть лицензию для конкретной версии. Здесь еще есть про CRT.
Я никак не могу понять одного, зачем удалять атрибут publicKeyToken из манифеста. Ведь положив неизмененное содержимое Microsoft.VC90.CRT в папку со своим приложением, ничего не нарушается, и приложение работает.
Чтобы сборка была не приватной, ее нужно установить в WinSxS, и сделать это можно только с помощью Windows Installer. Если же сборка лежит вместе с приложением, то она является приватной, и совершенно не важно, есть в манифесте этой сборки publicKeyToken или нет его там. Отличие в том, что без него, сборка не может быть неприватной.
Create a folder structure on the development computer that matches the folder structure to be used on the target computer. For this example, create a \bin folder and copy myapplication.exe there. Then create a \bin\mylibrary folder and copy MyLibrary.dll there.
On the development computer, from %PROGDIR%\Microsoft Visual Studio 8\VC\Redist\x86, copy Microsoft.VC80.CRT and Microsoft.VC80.MFC to \bin and to \bin\MyLibrary.
Copy the \bin folder to the target computer. On a target computer with manifest-based binding support (Windows XP Home Edition, Windows XP Professional, Windows Server 2003, Windows Vista) no further preparation is necessary. On a computer without such support (Windows 98, Windows 98 Second Edition, Windows Millennium Edition, Windows 2000), Microsoft.VC80.CRT and Microsoft.VC80.MFC must be on the path.
[...]
HAL>Я никак не могу понять одного, зачем удалять атрибут publicKeyToken из манифеста.
publicKeyToken является необязательной частью identity для application manifest, по которой производится поиск сборки. С таким же успехом можно имя поменять, но в коде инициализации crt есть привязка к имени.
HAL>Ведь положив неизмененное содержимое Microsoft.VC90.CRT в папку со своим приложением, ничего не нарушается, и приложение работает.
В таком случае, если в WinSxS присутствует необходимая сборка, то будет использована именно она (либо другая, с учетом механизма dependency redirection).
HAL>... Если же сборка лежит вместе с приложением, то она является приватной, и совершенно не важно, есть в манифесте этой сборки publicKeyToken или нет его там.
Наличие private сборки не является безусловным фактом ее использования.
Здравствуйте, http://alexyv.livejournal.com/, Вы писали:
HAL>И не нужно редактировать манифесты, удаляя publicKeyToken из них, — просто берем и используем.
В дополнение к тому, что написал Юрий Жмеренецкий: если в WinSxS присутстсвует более свежая версия, чем прописано в зависимостях манифеста, то будет использована именно она.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Здравствуйте, SchweinDeBurg, Вы писали: SDB>... если в WinSxS присутстсвует более свежая версия, чем прописано в зависимостях манифеста, то будет использована именно она.
... в таком случае, зачем alexyv в своём журнале в записи Side-by-side assemblies и их проблемы приложение, состоящее из нескольких модулей, каждый из которых ссылается на разные версии CRT, конфигурирует с помощью <dll-name>.2.config файлов? Потому что использует private сборку, расположенную в одной с приложением директории, вместо public сборки, установленной в WinSxS?
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>... в таком случае, зачем alexyv в своём журнале в записи Side-by-side assemblies и их проблемы приложение, состоящее из нескольких модулей, каждый из которых ссылается на разные версии CRT, конфигурирует с помощью <dll-name>.2.config файлов? Потому что использует private сборку, расположенную в одной с приложением директории, вместо public сборки, установленной в WinSxS?
Я, честно говоря, этот пост вижу впервые, поэтому сейчас ответить затрудняюсь, надо будет поэкспериментировать.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Здравствуйте, http://alexyv.livejournal.com/, Вы писали:
HAL>>И не нужно редактировать манифесты, удаляя publicKeyToken из них, — просто берем и используем.
SDB>В дополнение к тому, что написал Юрий Жмеренецкий: если в WinSxS присутстсвует более свежая версия, чем прописано в зависимостях манифеста, то будет использована именно она.
При условии, что установлены policy-файлы, перенаправляющие старые версии на новые.
В Visual Studio есть Merge-модули для Windows Installer, и в них сами библиотеки и policy-файлы разделены на два разных модуля. Таким образом, библиотеки более новой версии могут быть установлены в WinSxS, но старые версии перенаправляться на эту новую не будут, если *Policy-*.msm не был включен в инсталляционный пакет.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, SchweinDeBurg, Вы писали: SDB>>... если в WinSxS присутстсвует более свежая версия, чем прописано в зависимостях манифеста, то будет использована именно она.
R>... в таком случае, зачем alexyv в своём журнале в записи Side-by-side assemblies и их проблемы приложение, состоящее из нескольких модулей, каждый из которых ссылается на разные версии CRT, конфигурирует с помощью <dll-name>.2.config файлов?
Представь ситуацию: на компьютере установлена некотороая shared сборка версии 1.1, а приложение собрано с использованием сборки версии 1.0, но без проблем может работать и с версией 1.1. Поиск версии 1.0 закончится неудачей и (без дополнительных действий) приложение не будет загружено, т.к. требуется полное совпадение версий (в том числе). С помощью *.config файла можно описать перенаправление зависимости от версии 1.0 к версии 1.1 (см. атрибут bindingRedirect).
В том случае, если ты являешся автором shared сборки, то такого же результата можно добиться с помощью рublisher сonfiguration file (*.policy).
R>Потому что использует private сборку, расположенную в одной с приложением директории, вместо public сборки, установленной в WinSxS?
Нет, разница между shared/private сборками ортогональна конфликтам версий.
Besides the “bling”, notable changes include the Visual C++ 2010 CRT reverting to the traditional deployment model used by the Visual C++ 2003 CRT. More specifically, the CRT DLLs no longer use SxS binding (“Fusion”) and are now simply deployed to the “system32″ directory or to the application’s directory, as desired. Dropping SxS has some obvious disadvantages (SxS binding redirects would no longer be able to redirect applications that load a private copy of the CRT DLLs to updated versions with bug fixes and security updates) but presumably the pain of integrating SxS deployment into the setup process, which required either an MSI installation or pseudo-documented use of the SxS API, resulted in too much negative feedback and they chose to revert to the legacy approach.
... короче не будет больше Microsoft.VC90.ATL и Microsoft.VC90.CRT сборок, лежащих в C:\Windows\WinSxS директории, возвращаемся во временя DLL-Hell, теперь все эти DLL-ки снова будут находиться в C:\Windows\system32 ...
... я так понял народ, вместо того, чтобы разобраться, просто ниасилил SxS механизмы, стал линковаться статически с CRT и ATL и вкрай задолбал Microsoft багрепортами, вот они и откатились назад ...
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>... я так понял народ, вместо того, чтобы разобраться, просто ниасилил SxS механизмы, стал линковаться статически с CRT и ATL и вкрай задолбал Microsoft багрепортами, вот они и откатились назад ...
Нифига подобного. Я достаточно намучался с этим, и оказалось что тот единственный нормальный подход(с приватными сборками) и он оказался полурабочим.
Потому что если у вас все бинарники свалены в одно папку в которой лежите и сам црт, то проблем нет, а вот если у вас есть модули/плагины в других папках,
то даже если задать правильный путь в манифестах в папку с црт то всё равно это не работало у меня на висте, а работало только на ХР.
Инсталяции я даже не рассматриваю, потому что инсталяция — это зло.
+ сами мёрж модули и отдельные дистрибы которые идут со студией, ставятся очень раздражающе: например если у вас уже стоит црт в SxS, то инсталятор будет минут 10 опредлять, что не нада ничего ставить — п****ц.
А метода определения что оно уже стоит — нет.
Кароче все стандартные подходы — ограниченные и/или кривые.
Поэтому если у вас есть подпаки с ДДЛками то я делаю так:
Сделайте папку Bin в котрой будет exe, crt, манифесты и прочее
Модули/Плагины перед LoadLibrary копируйте в Bin и оттуда грузите.
Заодно получите подобие hot-deploy
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Kingofastellarwar, Вы писали: K>Сделайте папку Bin в котрой будет exe, crt, манифесты и прочее K>Модули/Плагины перед LoadLibrary копируйте в Bin и оттуда грузите. K>Заодно получите подобие hot-deploy :))
Круто! А где, собственно директория "Bin" должна жить? Не подскажете волшебное местечко в файловой системе? Т.е. я хочу сказать, что, например, в моём EXE приложении, "живёт" ActiveX, и приложение, к примеру, поднимается Internet Explorer'ом, отчего получает low integrity level на Висте, и соотвественно оно не то что в %PROGRAMMFILES%, оно даже в %APPDATA% ничего написать не сможет. Вот где от "hot-deploy" радости можно выгрести полные штаны!
:)
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, Kingofastellarwar, Вы писали: K>>Сделайте папку Bin в котрой будет exe, crt, манифесты и прочее K>>Модули/Плагины перед LoadLibrary копируйте в Bin и оттуда грузите. K>>Заодно получите подобие hot-deploy
R>Круто! А где, собственно директория "Bin" должна жить? Не подскажете волшебное местечко в файловой системе? Т.е. я хочу сказать, что, например, в моём EXE приложении, "живёт" ActiveX, и приложение, к примеру, поднимается Internet Explorer'ом, отчего получает low integrity level на Висте, и соотвественно оно не то что в %PROGRAMMFILES%, оно даже в %APPDATA% ничего написать не сможет. Вот где от "hot-deploy" радости можно выгрести полные штаны! R>
И что, даже в %ТМП% писать не может? Ну тогда прийдётся вам иметь весь букет SxS геморроя.
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, Kingofastellarwar, Вы писали: K>>Сделайте папку Bin в котрой будет exe, crt, манифесты и прочее K>>Модули/Плагины перед LoadLibrary копируйте в Bin и оттуда грузите. K>>Заодно получите подобие hot-deploy
R>Круто! А где, собственно директория "Bin" должна жить? Не подскажете волшебное местечко в файловой системе? Т.е. я хочу сказать, что, например, в моём EXE приложении, "живёт" ActiveX, и приложение, к примеру, поднимается Internet Explorer'ом, отчего получает low integrity level на Висте, и соотвественно оно не то что в %PROGRAMMFILES%, оно даже в %APPDATA% ничего написать не сможет. Вот где от "hot-deploy" радости можно выгрести полные штаны! R>
Ну и к тому же если прога является тем, что интегрируется в систему, то ясное дело что тут инсталяция показана. Иначе это равносильно как пытаться сделать портабл сервис ))
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Kingofastellarwar, Вы писали: K>Ну и к тому же если прога является тем, что интегрируется в систему, то ясное дело что тут инсталяция показана. Иначе это равносильно как пытаться сделать портабл сервис :)))))
Да не, у меня ничё нигде не интегрируется, просто обычное приложение, запускаемое либо из explorer.exe либо из svchost.exe (приложение является ещё и сервером COM объектов). Это я просто выдумываю ситуацию, чисто гипотетически. Потому как завтра мне вполне могут дать таск, в результате чего это всё придётся учитывать.
Сегодня я просто ставлю необходимые мне сборки используя merge модули. Однако упомянутая вами выше тормознутость msiexec.exe имеет место быть: заказчик мне прислал жалобу, что во время инсталляции софтины "On Vista, I observed that the installer left a dangling reference to "msiexec.exe". I had to kill it in task manager.", и произошло это именно во время установки этих merge модулей. А приватными эти сборки я также не могу сделать, ибо у меня приложение состоит из нескольких процессов, и эти процессы валяются по разным директориям. Я пока что, собственно, не приступил к поиску солюшена этой траблы: но на перспективу думаю найти способ установки в SxS кастомных shared сборок, и тогда положу туда CRT и ATL, и соответственно сносить их буду во время анинсталла.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, Kingofastellarwar, Вы писали: K>>Ну и к тому же если прога является тем, что интегрируется в систему, то ясное дело что тут инсталяция показана. Иначе это равносильно как пытаться сделать портабл сервис ))
R>Да не, у меня ничё нигде не интегрируется, просто обычное приложение, запускаемое либо из explorer.exe либо из svchost.exe (приложение является ещё и сервером COM объектов). Это я просто выдумываю ситуацию, чисто гипотетически. Потому как завтра мне вполне могут дать таск, в результате чего это всё придётся учитывать.
R>Сегодня я просто ставлю необходимые мне сборки используя merge модули. Однако упомянутая вами выше тормознутость msiexec.exe имеет место быть: заказчик мне прислал жалобу, что во время инсталляции софтины "On Vista, I observed that the installer left a dangling reference to "msiexec.exe". I had to kill it in task manager.", и произошло это именно во время установки этих merge модулей. А приватными эти сборки я также не могу сделать, ибо у меня приложение состоит из нескольких процессов, и эти процессы валяются по разным директориям. Я пока что, собственно, не приступил к поиску солюшена этой траблы: но на перспективу думаю найти способ установки в SxS кастомных shared сборок, и тогда положу туда CRT и ATL, и соответственно сносить их буду во время анинсталла.
Проблему отсутвия прав я тоже думал:
Если вы можете писать хотя б в %ТМП%, то можно сделать дополнительный ехе, который при запуске скопирует в TMP все бинарники всех процессов,
и запустит главный ехе передав ему как комманд лайн параметр путь к себе, чтобы он знал откуда был рождён.
У меня например в пылу борьбы с sxs гланый exe превратился в ничего не умеющий загрузчик, слинкованый статичесик и по минимому, который изначально предполагалось что будет определять чего не хватает для запуска сиситемы и самостоятельно устанавливать это беря из соотв папки.
Но красиво это сделать не получилось потому, что при ошибках в зависимостях при LoadLibrary винда мессадж боксы показывает, вместо того чтобы тихо ошибку вернуть.
Но на будущее я всё это оставил.
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
K>Но красиво это сделать не получилось потому, что при ошибках в зависимостях при LoadLibrary винда мессадж боксы показывает, вместо того чтобы тихо ошибку вернуть. K>Но на будущее я всё это оставил.
+1 тоже накушался этих MessageBox`ов — на кой это было надо делать Microsoft`у в толк никак не возьму. Стандартному самому обыкновенному юзеру от этих премудростей что "Not Found concrete.DLL" не тепло, не холодно. Нормальному "хомячку" это вообще мало что говорит, и вгоняет только лишний ступор, зато как клево это может ронять все подряд, слов нету Действительно, чем мешал старый подход с кодом ошибки — непонятно.
А как решили выкручиваться с поисками нужной ДЛЛ? Я без конца "жонглировал" SetCurrentDirectory, чтобы Windows увидела искомую DLL. Но это еще те танцы с бубнами, может есть какой способ покошернее?
Здравствуйте, Carc, Вы писали:
C>А как решили выкручиваться с поисками нужной ДЛЛ? Я без конца "жонглировал" SetCurrentDirectory, чтобы Windows увидела искомую DLL. Но это еще те танцы с бубнами, может есть какой способ покошернее?
Т.е.? Как ссылаемся на CRT ДЛЛки?
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Kingofastellarwar, Вы писали:
K>Здравствуйте, Carc, Вы писали:
C>>А как решили выкручиваться с поисками нужной ДЛЛ? Я без конца "жонглировал" SetCurrentDirectory, чтобы Windows увидела искомую DLL. Но это еще те танцы с бубнами, может есть какой способ покошернее?
K>Т.е.? Как ссылаемся на CRT ДЛЛки?
Та не! Я вообще о вопросе поиска нужной ДЛЛ.
У меня была проблема НЕ с CRT, а с реализациями RichEdit разных версий... (млин, эти ДЛЛ еще и одноименные через версию ).
Тут-то собсна все и началось: если в двух словах, то нужный RichEdit в общем случае было известно где искать, и как правило он там есть. Но он цепляет еще одну DLL, причем похоже откуда-то из своей собственной DllMain — то бишь еще до малейшей попытки хоть что-то поюзать из загруженной DLL, пыталась грузиться эта самая дополнительная DLL...
Вот тут все и началось: если в псевдокоде, то что-то подобного вида Шаг 1) находим полный путь к нужной версии с RichEdit.DLL Шаг 2) ставим новую текущую папку SetCurrentDirectory(папка_с_той_самой_дополнительной_длл) (ее тоже примерно известно где искать) Шаг 3) Грузим RichEdit.DLL из п.1 указавая полный путь (дабы не баловала с другими версиями одноименной RichEdit.DLL). Шаг 4) При загрузке RichEdit.DLL в п.3, т.к. мы уже выставили SetCurrentDirectory в п.2. — то по этому пути и искалась эта самая дополнительная ДЛЛ, ну и успешно загружалась. Шаг 5) Возвращаем предыдущий SetCurrentDirectory из п.2.
В противном случае, если выкинуть эти бубны, на загрузке RichEdit.DLL вылетал MessageBox — мол не нашла еще одну ДЛЛ (причем этот MessageBox вообще ни к селу не к городу был, вплоть до Access Violation)
Уф, пока написал аж у самого чуть моск не свело. А уж когда на реальный код смотрю, там вообще без мата никак, несмотря на всевозможнейшие автоматизации с SetCurrentDirectory.
Вот от такого дремучего кода и хотелось бы избавиться!
Посматривал в сторону всяких SearchPath, но руки так и не дошли. Собсна отсюда и вопрос: а туда ли я полез? И нету ли способа попроще, а то так и хочется исходник переименовать в "Ничего_Не_Трогайте_НИКОГДА.h"
Здравствуйте, Carc, Вы писали:
K>>Здравствуйте, Carc, Вы писали:
Ааа не, такой проблемы не было.
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Carc, Вы писали: C>Посматривал в сторону всяких SearchPath, но руки так и не дошли. Собсна отсюда и вопрос: а туда ли я полез? И нету ли способа попроще, а то так и хочется исходник переименовать в "Ничего_Не_Трогайте_НИКОГДА.h" :(
Мне как-то тоже было необходимо внести свои корректировки в процесс поиска нужной DLL. Но Current Directory я не трогал. ИМХО, муторно это туда сюда гонять эту директорию: то она здесь, то она там, то опять здесь, так легко и провтыкать где-то в коде ненароком и отловить нехилую бажину. Я вместо этого изменял переменную окружения PATH для своего процесса.
Ну допустим, требуемая DLL валяется по следующему пути "С:\Program Files\Dazdraperma\ProletariiVsehStranSoyedinyaytes.DLL", и директория в системной PATH не имеется, и эта директория не является текущей директорией процесса. Я делал примерно так:
Таким образом можно однажды при запуске апликухи добавить нужную директорию (или все интересующие директории) в переменную окружения PATH, а дальше по коду просто вызывать LoadLibrary(_T("ProletariiVsehStranSoyedinyaytes.DLL")) (или вызывать LoadLibrary для всех интересующих модулей, раскиданных по всяким папкам) и всё работает, и не надо туда сюда переписывать Current Directory.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Kingofastellarwar, Вы писали: K>Но красиво это сделать не получилось потому, что при ошибках в зависимостях при LoadLibrary винда мессадж боксы показывает, вместо того чтобы тихо ошибку вернуть. K>Но на будущее я всё это оставил.
Кстати MessageBox'овая болячка банально может быть вылечена перехватом Win32 API вызовов по методу описанному в книге Рихтера. Перехватив вызов всех возможных MessageBox'овых функций, можно не редиректить на вызов оригинальных функций, а просто забить на этот мессадж и ничего не показывать.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, Carc, Вы писали: C>>Посматривал в сторону всяких SearchPath, но руки так и не дошли. Собсна отсюда и вопрос: а туда ли я полез? И нету ли способа попроще, а то так и хочется исходник переименовать в "Ничего_Не_Трогайте_НИКОГДА.h"
R>Мне как-то тоже было необходимо внести свои корректировки в процесс поиска нужной DLL. Но Current Directory я не трогал. ИМХО, муторно это туда сюда гонять эту директорию: то она здесь, то она там, то опять здесь, так легко и провтыкать где-то в коде ненароком и отловить нехилую бажину. Я вместо этого изменял переменную окружения PATH для своего процесса.
R>Ну допустим, требуемая DLL валяется по следующему пути "С:\Program Files\Dazdraperma\ProletariiVsehStranSoyedinyaytes.DLL", и директория в системной PATH не имеется, и эта директория не является текущей директорией процесса. Я делал примерно так:
R>Таким образом можно однажды при запуске апликухи добавить нужную директорию (или все интересующие директории) в переменную окружения PATH, а дальше по коду просто вызывать LoadLibrary(_T("ProletariiVsehStranSoyedinyaytes.DLL")) (или вызывать LoadLibrary для всех интересующих модулей, раскиданных по всяким папкам) и всё работает, и не надо туда сюда переписывать Current Directory.
Не-е-е! Не катит! Уж больно глобальное решение — влияет на все в пределах процесса, чем такое может кончиться боязно и подумать
1) В MSDN сказано что PATH проверяется последней когда ищется DLL, то бишь в моем случае как нефиг делать может загрузиться искомая DLL из других путей (%SYSDIR%, %WINDIR% и.т.д.) ибо найдется раньше — а библиотечка вполне с одноименным и распространенным названием (RichEd20.DLL — часть PSDK, причем имя файла DLL одно и тоже, а версий компонентов там как минимум 3 точно может быть — а это было важно по сути задачи).
2) Установка PATH да к тому же для всего процесса влияет на поиск всех грузящихся ДЛЛ — чем это закончится для соседнего кода неизвестно — ну ее в болоту это глобализацию...
3) Если поставить еще одну директорию в PATH, то одному господу богу, где, и как, и кто может загрузиться за компанию. В моем случае искомая библиотека была в недрах Common Files\Microsoft Shared. Если я этот путь положу в PATH, то что оттуда и еще какое-нить мс-офисное барахло подгрузится стремно и подумать... А вот MS-офисных расширений, не пойми чем занимающихся в моем адресном пространстве точно не нужно — и так хваленой Windows-ской совместимости с головой хватает Это как некая конкретизация п.2
4) Трабла с SetCurrentDirectory была мрачно автоматизирована в стиле идиомы "владелец ресурса"
нечто вроде
class CAutoDirectory {
CString m_strPrevDir;
operator new();//new - в private его батеньку, в private чтобы никто и никогда и ни при каких! public:
//конструктор изменяет текущую директорию
//и запоминает предыдущую
CAutoDirectory(CString strNewDir)
{
GetCurrentDirectory(m_strPrevDir);
SetCurrentDirectory(strNewDir);
}
//деструктор ставит обратно предыдущую директорию
~CAutoDirectory()
{
SetCurrentDirectory(m_strPrevDir);
};
//ну и в коде понеслось
//объявляем на стеке, деструктор сам все вернет на круги своя
CAutoDirectory directory_owner(strNewDir);
Ну это так, класс навскидку написан, как иллюстрация — в реальном коде конечно же и проверки всякие были, и прочая муть чтобы лишней работы не делать. В таком варианте всеми траблами мается сам компилятор, об этом заботиться уже не приходиться.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, Kingofastellarwar, Вы писали: K>>Но красиво это сделать не получилось потому, что при ошибках в зависимостях при LoadLibrary винда мессадж боксы показывает, вместо того чтобы тихо ошибку вернуть. K>>Но на будущее я всё это оставил.
R>Кстати MessageBox'овая болячка банально может быть вылечена перехватом Win32 API вызовов по методу описанному в книге Рихтера. Перехватив вызов всех возможных MessageBox'овых функций, можно не редиректить на вызов оригинальных функций, а просто забить на этот мессадж и ничего не показывать.
1. можно поюзать функцию SetErrorMode!
2. Или уж не проще ли тогда хук поставить причем именно на поток, который грузит ДЛЛ? И не мудрить с перехватом, зачем недокументированное что-то юзать?
C>2. Или уж не проще ли тогда хук поставить причем именно на поток, который грузит ДЛЛ?
Хук на что можно в этот момент поставить? На создание окошка?
C>И не мудрить с перехватом, зачем недокументированное что-то юзать?
Кстати перехват выполняется с помощью tool-help функций (CreateToolhelp32Snapshot, Process32First, Process32Next, Module32First, Module32Next, etc.) и с помощью функций и структур для работы с PE образами (например ImageDirectoryEntryToDataEx, PIMAGE_SECTION_HEADER, PIMAGE_IMPORT_DESCRIPTOR, PIMAGE_THUNK_DATA, etc.), ну и конечно таких функций как VirtualProtectEx, VirtualQueryEx и так далее, т.е., как видите, используется исключительно опубликованное и легальное Win32 API, ничего недокументированного здесь нет. А в случае, если всё это проходит в рамках собственного процесса, и вы никуда не внедряете свой код и не роетесь в чужих адресных пространствах, то никаких проблем с Integrity барьерами, межпроцессным взаимодействием и Security не будет происходить, и такое приложения даже без проблем пройдёт Microsoft Windows Vista Сертификацию.
C>1. можно поюзать функцию SetErrorMode!
Согласен.
C>Не-е-е! Не катит! Уж больно глобальное решение — влияет на все в пределах процесса, чем такое может кончиться боязно и подумать :)
:):)
Ну это вы, Carc, совсем уж армагеддоный случай описываете. PATH именно потому и проверяется последней, потому что в PATH может лежать всякого левого мусора. Плюс я добавлял директорию в PATH чтобы искать свои собственные DLL'ки, которые уникальны и где-попало валяться не будут, и делалось это просто для удобства, чтобы в LoadLibrary писать не полный путь к библиотеке, а только её имя.
C>Если поставить еще одну директорию в PATH, то одному господу богу, где, и как, и кто может загрузиться за компанию.
Ну это означает только лишь то, что добалять директори в PATH надо с умом. Если ты добавляешь в PATH директорию %PROGRAM_FILES%\MyApp\PluginModules, где лежат пара/тройка ваших собственных DLL и более ничего, то никакой соседний код никакой мусор туда не загрузит.
C>Трабла с SetCurrentDirectory была мрачно автоматизирована в стиле идиомы "владелец ресурса" C>class CAutoDirectory C>CAutoDirectory directory_owner(strNewDir);
Интересное решение, главное только чтобы после создания и до разрушения объекта directory_owner не выполнялся код, который может сломаться, или отработать некорректно, при смене текущей диретории. Ведь в этом месте потенциально может выполниться код, который "одному господу богу известно" что сможет загрузить за компанию, в том числе и "какое-нить мс-офисное барахло", и вообще весь вышеописанный армагеддон, помноженный на то, что CurrentDirectory имеет намного больший приоритет чем PATH.
C>В моем случае искомая библиотека была в недрах Common Files\Microsoft Shared.
Согласен, что такую директорию добавлять в PATH опасно :):)
Но изначально речь шла не о RichEd20.DLL, а о собственных DLL, которые хочется разместить не всей кодлой в одной с приложением директории, а разбить их логически по sub-директориям. Это видно, если почитать ветку с самого начала. В таком случае, конечно что SetCurrentDirectory решение, что GetEnvironmentVariable/SetEnvironmentVariable решение подойдут более чем, однако, имхо: правильнее будет использовать Side-by-side механизмы в таких случаях.
На самом деле, что решения с помощью SetCurrentDirectory, что решения с помощью GetEnvironmentVariable/SetEnvironmentVariable — есть ужасно кривые способы борьбы с ужасной проблемой под названием DLL-Hell. И применялись эти решения исключительно до тех пор, пока Microsoft не предоставила "нормальный" механизм решения проблем DLL-Hell'а: Isolated applications и Side-by-side assemblies. Лично я использовал GetEnvironmentVariable/SetEnvironmentVariable до тех пор, пока не открыл эту ветку на rsdn, где Юрий Жмеренецкий подсказал мне
приложения: до этого я в манифестах ссылался только на shared assemblies (CRT/ATL/MFC/Common-Controls/etc.), теперь, я делаю собственные private сборки и на них же ссылаюсь в манифесте приложения. И это легальный документированный путь, который прекрасно работает без переписывания PATH и без перемещений туды/сюды текущей директории процесса.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
C>>2. Или уж не проще ли тогда хук поставить причем именно на поток, который грузит ДЛЛ? R>Хук на что можно в этот момент поставить? На создание окошка?
C>>И не мудрить с перехватом, зачем недокументированное что-то юзать? R>Кстати перехват выполняется с помощью tool-help функций (CreateToolhelp32Snapshot, Process32First, Process32Next, Module32First, Module32Next, etc.) и с помощью функций и структур для работы с PE образами (например ImageDirectoryEntryToDataEx, PIMAGE_SECTION_HEADER, PIMAGE_IMPORT_DESCRIPTOR, PIMAGE_THUNK_DATA, etc.), ну и конечно таких функций как VirtualProtectEx, VirtualQueryEx и так далее, т.е., как видите, используется исключительно опубликованное и легальное Win32 API, ничего недокументированного здесь нет. А в случае, если всё это проходит в рамках собственного процесса, и вы никуда не внедряете свой код и не роетесь в чужих адресных пространствах, то никаких проблем с Integrity барьерами, межпроцессным взаимодействием и Security не будет происходить, и такое приложения даже без проблем пройдёт Microsoft Windows Vista Сертификацию.
1) Угу — только нафига весь этот мудреж с перехватом, который не шибко нравится всяким антивирям, если можно мрачно поставить хук и сделать все тоже самое!?! К чему выпендреж то?
2) Код загрузки конкретной ДЛЛ — это очень глубокий код, в конкретном приложении может быть зарыто ох как глубоко. И на тебе нах, есть нюанззз — оказывается там в недрах живет перехват... И о чудо, вдруг выясняется что другой разработчик в другом конце приложения тоже учинил перехват — и вдруг возникают какие-то ошибки взаимодействия 2-ух перехватов!?! И дело тут только в одном: людям свойственно ошибаться, а значит рано или поздно ошибемся. Каким образом можно вкурить, что загрузка ДЛЛ приводит к перехвату — пока в этот код носом не упрешься в голову не придет.
Собственно все это о том, зачем городить такой огород, который содержит потенциальные возможности ошибок, причем ошибок очень неприятных тем, что причина косячка в одном месте, а вылезает косячок совершенно на другом конце приложения. И более того, не в напрочь просветленному мужу и не придет в голову что LoadLibrary ведет к проблеме? На кой сложность, если можно проще?
C>>1. можно поюзать функцию SetErrorMode! R>Согласен.
C>>Не-е-е! Не катит! Уж больно глобальное решение — влияет на все в пределах процесса, чем такое может кончиться боязно и подумать R> R>Ну это вы, Carc, совсем уж армагеддоный случай описываете. PATH именно потому и проверяется последней, потому что в PATH может лежать всякого левого мусора. Плюс я добавлял директорию в PATH чтобы искать свои собственные DLL'ки, которые уникальны и где-попало валяться не будут, и делалось это просто для удобства, чтобы в LoadLibrary писать не полный путь к библиотеке, а только её имя.
Согласен — не спорю, несколько частный случай привел. Мне не нравится вариант с PATH тем, что
а) Влияет на весь процесс
б) Влияет раз и навсегда (ну по идее ставим переменную один раз и не убираем ее, так?)
Глобализация ведет к лишним, а главное не то чтобы неявным, а весьма и веьсма глубоко зарытым зависимостям, которые неизвестно каким боком, когда и куда стрельнут — а если ружо на стене висит, то ружно рано или поздно все-таки пальнет
А т.к. такие зависимости еще и глубоко зарытые, то с отладчиком наперевес придется рыться в коде ну очень долго ибо неясно откуда вообще проблема.
А т.к. зависимость на весь процесс — то еще и весь код перерыть придется (включая код сторонних ДЛЛ)
C>>Если поставить еще одну директорию в PATH, то одному господу богу, где, и как, и кто может загрузиться за компанию. R>Ну это означает только лишь то, что добалять директори в PATH надо с умом. Если ты добавляешь в PATH директорию %PROGRAM_FILES%\MyApp\PluginModules, где лежат пара/тройка ваших собственных DLL и более ничего, то никакой соседний код никакой мусор туда не загрузит.
C>>Трабла с SetCurrentDirectory была мрачно автоматизирована в стиле идиомы "владелец ресурса" C>>class CAutoDirectory C>>CAutoDirectory directory_owner(strNewDir); R>Интересное решение, главное только чтобы после создания и до разрушения объекта directory_owner не выполнялся код, который может сломаться, или отработать некорректно, при смене текущей диретории. Ведь в этом месте потенциально может выполниться код, который "одному господу богу известно" что сможет загрузить за компанию, в том числе и "какое-нить мс-офисное барахло", и вообще весь вышеописанный армагеддон, помноженный на то, что CurrentDirectory имеет намного больший приоритет чем PATH.
Нет, не совсем так.
Если код с C++ exception — то объект гарантировано разрушиться, и вернет свою прежнюю директорию. Ну а если мы ловим SEH исключение (и не ждем его, не обрабатываем), то тут и разговаривать не о чем — код уже понесло как лося по болоту, тут о каком-то дюже правильном выполнении программы вообще говорить не приходится.
Согласен с Вами что вся это моя муть с Set\GetCurrentDirectory — должна быть написана максимально аккуратно.
Но, есть одно "но" — вся эта муть происходит на стеке в конкретной функции, поэтому нужно очень аккуратненько спроектировать функцию, все остальное от этого решения не зависит. Имхо, это лучше, чем бороться с последствиями каких-то глобальных настроек для всего процесса, выставленных на весь сеанс работы. Потенциально, имею ввиду, лучше.
C>>В моем случае искомая библиотека была в недрах Common Files\Microsoft Shared. R>Согласен, что такую директорию добавлять в PATH опасно R>Но изначально речь шла не о RichEd20.DLL, а о собственных DLL, которые хочется разместить не всей кодлой в одной с приложением директории, а разбить их логически по sub-директориям. Это видно, если почитать ветку с самого начала. В таком случае, конечно что SetCurrentDirectory решение, что GetEnvironmentVariable/SetEnvironmentVariable решение подойдут более чем, однако, имхо: правильнее будет использовать Side-by-side механизмы в таких случаях.
ОК, не спорю — немного отклонились.
А что мне даст Side-By-Side?
R>На самом деле, что решения с помощью SetCurrentDirectory, что решения с помощью GetEnvironmentVariable/SetEnvironmentVariable — есть ужасно кривые способы борьбы с ужасной проблемой под названием DLL-Hell. И применялись эти решения исключительно до тех пор, пока Microsoft не предоставила "нормальный" механизм решения проблем DLL-Hell'а: Isolated applications и Side-by-side assemblies. Лично я использовал GetEnvironmentVariable/SetEnvironmentVariable до тех пор, пока не открыл эту ветку на rsdn, где Юрий Жмеренецкий подсказал мне
приложения: до этого я в манифестах ссылался только на shared assemblies (CRT/ATL/MFC/Common-Controls/etc.), теперь, я делаю собственные private сборки и на них же ссылаюсь в манифесте приложения. И это легальный документированный путь, который прекрасно работает без переписывания PATH и без перемещений туды/сюды текущей директории процесса.
Здравствуйте, Carc, Вы писали: C>+1 А вот за ссылки, спасибо! :up:
:):):)
... вообще-то эти ссылки ведут к истоку данного треда мессаг.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, Carc, Вы писали: C>>+1 А вот за ссылки, спасибо!
R> R>... вообще-то эти ссылки ведут к истоку данного треда мессаг.
Чего то я зарапортовался Всё — хорош кодить, переходим к пункту "Разное"
По моему вы тут намешали проблему поиска црт/мфс/атл через манифесты и проблему загрузки нужных длл при обычном подходе
загрузка длл через манифесты апи функция или переменными окружения не управляется в принципе
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Carc, Вы писали:
C>1) Угу — только нафига весь этот мудреж с перехватом, который не шибко нравится всяким антивирям, если можно мрачно поставить хук и сделать все тоже самое!?! К чему выпендреж то?
На сколько мне известно антивирям он не нравится только тогда, когда вы пытаетесь это сделать в рамках чужого процесса, и то только потому, что вы для этого должны внедрить в этот чужеродный процесс свой модуль, и антивири ругаться будут именно на это. В рамках же своего процесса все эти действия по перехвату есть вполне легальные действия и никакой антивирь, или кто-либо вообще, не имеет право на меня материться. + ИМХО: установка хуков есть не меньший выпендрёж!
C>2) Код загрузки конкретной ДЛЛ — это очень глубокий код, в конкретном приложении может быть зарыто ох как глубоко. И на тебе нах, есть нюанззз — оказывается там в недрах живет перехват... И о чудо, вдруг выясняется что другой разработчик в другом конце приложения тоже учинил перехват — и вдруг возникают какие-то ошибки взаимодействия 2-ух перехватов!?! И дело тут только в одном: людям свойственно ошибаться, а значит рано или поздно ошибемся. Каким образом можно вкурить, что загрузка ДЛЛ приводит к перехвату — пока в этот код носом не упрешься в голову не придет.
Речь идёт не о перехвате функций LoadLibrary*(), а речь идёт о перехвате функций MessageBox*(). При этом я не вижу никаких проблем с тем, что в другом конце приложения другой разработчик тоже учинил перехват. В таком случае раньше перехват получит выполнение тот, кто по ходу выполнения программы первым устанавливает перехватчик, затем второй выполнение получит второй перехватчик, и так далее. Вот и всё. Если какой-либо из перехватчиков решит оборвать цепь вызовов (т.е. не вызовет в своём коде оригинальную функцию), то остальные управления, понятно, не получат. Но извините по большому счёту в HOOK'ах поведение то же самое: та же цепочка перехватов, так же один item этой цепи может её прервать.
Если честно, вообще не вижу никакой идеологической разницы между установками HOOK'ов, и перехватами вызовов функций, экспортируемых из некой длл. Что одно, что другое — суть хуки. Только реализация отличается.
Я просто хочу сказать, что и один и другой способ одинаково легальны, и если они одинакого могут решить конкретную задачу, то какой из способов выбрать лично вам и лично мне, это уже, извините, спор о том "какой вам цвет больше нравится".
И вообще, мне кажется, что наше обсуждение о том, что именно лучше/удобнее/проще/нагляднее/etc., хуки aka "HOOKS" или хуки aka "Перехват API вызовов", — есть флуд: ветка совсем о другой теме.
C>Если код с C++ exception — то объект гарантировано разрушиться, и вернет свою прежнюю директорию.
Нет, выше шла речь об армагедоне во время выполнения функции, создающей объект directory_owner. Там ведь с таким же успехом может отработать скрытый от глаз, где-то в недрах какого-то API, отработать код, который будет пользоваться этой текущей директорией. Я просто говрю, что опастнось армагеддона там не меньшая, а наоборот большая, т.к. CurrentDirectory имеет намного больший приоритет чем PATH. Дописывая в конец локальной переменной PATH, вы не перекрываете ничего. Меняя текущую директорию, вы перекрываете не только PATH, но и "Системный каталог Windows", "Основной каталог Windows", и всё, что находится в PATH. И таким образом что-то, что лежит в вашей "новой" текущей директории, начинает угрожать намного большему количеству модулей , а особенно системным модулям, что, согласитесь опаснее!
C>Согласен — не спорю, несколько частный случай привел. Мне не нравится вариант с PATH тем, что C>а) Влияет на весь процесс C>б) Влияет раз и навсегда (ну по идее ставим переменную один раз и не убираем ее, так?)
Я согласен, что установка текущей директории влияет на работу только одной функции, а не всего процесса. Это, вообще-то, — очевидно.
Я говорю о другом. Смотря что именно прописывать в PATH.
Если "Common Files\Microsoft Shared", тогда да, это жопа. В таком варианте контролировать текущую директорию намного безопаснее чем, прописывать это добро в PATH.
Если "%PROGRAM_FILES%\MyApp\PluginModules", содержание которой вы контролируете, то никакой жопы здесь нет. И добавить эту директорию в PATH будет намного удобнее, чем контролировать текущую директорию процесса. Кроме того, контролируя переменную PATH, вы работаете с самым последним звеном списка поиска модулей, а это значит потенциально менее вероятна опасность перекрыть какой-нибудь важный системный модуль (это, конечно, всё в виду соображений о наступившем армагедеце, который Вы рисуете).
C>Глобализация ведет к лишним, а главное не то чтобы неявным, а весьма и веьсма глубоко зарытым зависимостям, которые неизвестно каким боком, когда и куда стрельнут — а если ружо на стене висит, то ружно рано или поздно все-таки пальнет
С другой стороны "зубов бояться, в рот не ...", т.е переменную PATH может загадить всяким непотребом не только свой процесс, получить мусор можно от процесса-родителя, если какую-нибудь какашку пропишут в системную PATH. Поэтому длительные часы отладки вы можете получить и без ковыряния локально-процессной переменной PATH. И, думаю, именно поэтому переменную PATH разработчики Windows засунули в самый конец списка поиска модулей, ибо она редактируема как локально, так и глобально.
C>А что мне даст Side-By-Side?
В конкретно вашем случае поиска RichEdit20.DLL — абсолютно ничего. И собственно, чтобы порешать проблему DLL-HELL'а, вам ничего не остаётся, кроме контроля над текущей директорией процесса либо контроля над локальной переменной PATH.
В конкретно моём случае размещения собственных модулей в подпапках директории приложения, Side-By-Side избавляет меня от этих двух корявых методов борьбы с Dll-Hell'ом. Собственно говря, именно для этого я и создавал эту ветку форума.
:)
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Kingofastellarwar, Вы писали:
K>По моему вы тут намешали проблему поиска црт/мфс/атл через манифесты и проблему загрузки нужных длл при обычном подходе K>загрузка длл через манифесты апи функция или переменными окружения не управляется в принципе
Да нет же. Если у меня приложение MyApp.exe в результате линковки зависит от ToolDll1.dll, ToolDll3.dll и ToolDll3.dll, то я могу поместить их в подпапку "ToolAssembly", с помощью манифестов объявить её private assembly, опять же с помощью манифестов сослаться на сборку "ToolAssembly" в MyApp.exe.manifest, и моё приложение разрешит все свои зависимости без каких бы то ни было манипуляций с PATH или Current Dir. Это собственно то, что мне и нужно дабы не городить всякие корявости с помощью GetEnvironmentVariable/SetEnvironmentVariable или с помощью GetCurrentDirectory/SetCurrentDirectory.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R>Здравствуйте, Carc, Вы писали:
C>>Согласен — не спорю, несколько частный случай привел. Мне не нравится вариант с PATH тем, что C>>а) Влияет на весь процесс C>>б) Влияет раз и навсегда (ну по идее ставим переменную один раз и не убираем ее, так?) R>Я согласен, что установка текущей директории влияет на работу только одной функции, а не всего процесса. Это, вообще-то, — очевидно. R>Я говорю о другом. Смотря что именно прописывать в PATH. R>Если "Common Files\Microsoft Shared", тогда да, это жопа. В таком варианте контролировать текущую директорию намного безопаснее чем, прописывать это добро в PATH. R>Если "%PROGRAM_FILES%\MyApp\PluginModules", содержание которой вы контролируете, то никакой жопы здесь нет. И добавить эту директорию в PATH будет намного удобнее, чем контролировать текущую директорию процесса. Кроме того, контролируя переменную PATH, вы работаете с самым последним звеном списка поиска модулей, а это значит потенциально менее вероятна опасность перекрыть какой-нибудь важный системный модуль (это, конечно, всё в виду соображений о наступившем армагедеце, который Вы рисуете).
C>>Глобализация ведет к лишним, а главное не то чтобы неявным, а весьма и веьсма глубоко зарытым зависимостям, которые неизвестно каким боком, когда и куда стрельнут — а если ружо на стене висит, то ружно рано или поздно все-таки пальнет R>С другой стороны "зубов бояться, в рот не ...", т.е переменную PATH может загадить всяким непотребом не только свой процесс, получить мусор можно от процесса-родителя, если какую-нибудь какашку пропишут в системную PATH. Поэтому длительные часы отладки вы можете получить и без ковыряния локально-процессной переменной PATH. И, думаю, именно поэтому переменную PATH разработчики Windows засунули в самый конец списка поиска модулей, ибо она редактируема как локально, так и глобально.
PATH еще редактируема через ветку реестра HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths. Ниже можно обнаружить множество программ, например firefox.exe и excel.exe, которые, кроме полного пути к исполняемому файлу (в параметре по умолчанию), объявляют параметр Path, содержимое которого будет добавлено в переменную Path при запуске процесса.
И хотя указание Path в этой ветке не влияет на порядок поиска DLL, используемый по умолчанию, это позволяет запускать exe файл через команду Run/Выполнить, не указывая полного пути. А добавление Path к системной PATH позволит exe файлу загрузить необходимые библиотеки.
Стоит отметить, что начиная с Windows XP SP2, текущий каталог просматривается после всех системных, как раз перед тем, как искать в PATH, при условии, что включен SafeDllSearchMode (по умолчанию включен, начиная с Windows XP SP2). Это отодвигает текущий каталог почти в самый низ поиска, и можно словить трудно отлавливаемые баги, если вдруг Required.dll загрузится из системных путей, а не из текущего каталога.
A>Стоит отметить, что начиная с Windows XP SP2, текущий каталог просматривается после всех системных, как раз перед тем, как искать в PATH, при условии, что включен SafeDllSearchMode (по умолчанию включен, начиная с Windows XP SP2). Это отодвигает текущий каталог почти в самый низ поиска, и можно словить трудно отлавливаемые баги, если вдруг Required.dll загрузится из системных путей, а не из текущего каталога.
Внимательно читаем что я написал выше:
LoadLibrary(полный_путь_к_DLL); //чтобы не искала одноименные ДЛЛ где бы то ни было
Так что пофиг порядок поиска для одноименных ДЛЛ в системных папках. Фокусы с SetCurrentDirectory применялись в вышенаписанном для другой проблемы...
R>При этом я не вижу никаких проблем с тем, что в другом конце приложения другой разработчик тоже учинил перехват. В таком случае раньше перехват получит выполнение тот, кто по ходу выполнения программы первым устанавливает перехватчик, затем второй выполнение получит второй перехватчик, и так далее. Вот и всё. Если какой-либо из перехватчиков решит оборвать цепь вызовов (т.е. не вызовет в своём коде оригинальную функцию), то остальные управления, понятно, не получат. Но извините по большому счёту в HOOK'ах поведение то же самое: та же цепочка перехватов, так же один item этой цепи может её прервать.
В написанном ошибка. Здесь, конечно же имеется в виду, что тот кто позже во время выполнения устанавливает перехватчик, тот раньше получает управление при вызове перехватываемой функции. Т.е. порядок вызовов перехватчиков обратный порядку их инсталляции.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, alexyv, Вы писали: A>Стоит отметить, что начиная с Windows XP SP2, текущий каталог просматривается после всех системных, как раз перед тем, как искать в PATH, при условии, что включен SafeDllSearchMode (по умолчанию включен, начиная с Windows XP SP2). Это отодвигает текущий каталог почти в самый низ поиска, и можно словить трудно отлавливаемые баги, если вдруг Required.dll загрузится из системных путей, а не из текущего каталога.
Я, кстати, был уверен, что со времён Win2k алгоритм поиска неизменен, и не знал, что, начиная с Windows XP SP2, во время работы SafeDllSearchMode'а текущая директория перемещается со второго (начиная сверху) списка поиска DLL на пятое место (т.е. предпоследний пункт). В виду этого манипуляции с текущей директорией процесса конечно же становятся менее опасными в силу уменьшения их приоритета.
, меня лично огорчило.
Единственное, что мне непонятно, почему Side-By-Side механизм не подчиняется обычным правилам поиска DLL, а обязывает assembly лежать рядом с модулем, для которого разрешаются зависимости (в случае с private assembly), либо обязывает assembly лежать WinSxS директории (в случае с public assembly). Было бы очень удобно добавлять дополнительные директории поиска в алгоритм поиска SxS-загрузчика. Например, что-то вроде локально-процессной переменной окружения SxS-PATH или что-то вроде этого. Т.е. возникает такое ощущение, что механизм SxS ещё достаточно сырой, и возможно, разработчики Microsoft будут в будущем расширять эту функциональность.
Хотя — хз, если по сей день от Microsoft'а так и не дождались "толкового решения" проблемы Dll-Hell (а время-то уже сколько прошло!), вряд ли от Microsoft'а можно этого ожидать в ближайшем будущем.
Короче, сидят и пинают они в рабочее время, вместо того чтобы усовершенствовать Core операционки, а не добавлять в новые версии тучу красивостей. Слава богу, хоть Windows Security обновили, и то хорошо.
"Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
Здравствуйте, Rakafon, Вы писали:
R> Было бы очень удобно добавлять дополнительные директории поиска в алгоритм поиска SxS-загрузчика. Например, что-то вроде локально-процессной переменной окружения SxS-PATH или что-то вроде этого.
Для динамически загружаемых модулей перед вызовом LoadLibrary можно сформировать необходимый контекст активации с помощью CreateActCtx:
ACTCTX::lpAssemblyDirectory
The base directory in which to perform private assembly probing if assemblies in the activation context are not present in the system-wide store.