Как проверить версию dll

Обновлено: 21.11.2024

Компонентно-ориентированное программирование должно позволять клиентам и компонентам развиваться отдельно.

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

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

Общие компоненты, с другой стороны, могут вызвать много проблем с управлением версиями. Общие компоненты хранятся в каком-то глобально известном месте и используются несколькими приложениями. Тем не менее, требуется зрелая компонентная технология, позволяющая нескольким приложениям совместно использовать серверные компоненты.

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

Модели развертывания сборки

Частная сборка подразумевает именно это: каждое клиентское приложение поддерживает свою собственную частную локальную копию сборки. Развернуть приватную сборку так же просто, как скопировать ее в каталог использующего ее приложения. Хотя во время установки клиентские приложения обычно развертывают все необходимые частные сборки, ничто не мешает позже скопировать новую частную сборку, если номер версии совместим с тем, что ожидает клиентское приложение. Это, в свою очередь, допускает разные жизненные циклы клиента и сервера и позволяет им развиваться по отдельности.

При копировании новой версии частной сборки в клиентский каталог, если у приложения есть предыдущая копия сборки, новая копия переопределяет старую копию, поскольку в файловом каталоге не может быть нескольких файлов с одинаковыми именами. Частные сборки обычно обратно совместимы, поскольку они должны поддерживать все функции, доступные в предыдущей версии. Если бы это было не так, старое клиентское приложение перестало бы работать при попытке доступа к функциям новой версии, которая отличается от старой версии.

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

Номер версии сборки

Номер версии записывается в манифесте сборки сервера. Когда разработчик клиента добавляет ссылку на серверную сборку, клиентская сборка записывает в своем манифесте имя и точную версию серверной сборки, для которой она была скомпилирована. Это означает, что если клиент использует класс MyClass из сборки MyAssembly версии 1.2.3.4, то в манифесте клиента будет записано, что для работы клиенту требуется версия 1.2.3.4 MyAssembly, и будет содержаться такая текстовая строка:

Во время выполнения .NET определяет расположение запрошенной сборки, и клиент всегда получает совместимую сборку. Если совместимая сборка не найдена, возникает исключение. Вопрос в том, "что представляет собой совместимая сборка?" Чтобы ответить на этот вопрос, следует внимательно изучить структуру номера версии сборки.

Номер версии состоит из четырех цифр: номер основной версии, номер дополнительной версии, номер сборки и номер редакции. На рис. 1 эти номера указаны по порядку. Правила совместимости просты: совместимая сборка должна иметь точный основной и дополнительный номера версии, которые запрашивает клиентский манифест. Номер сборки и номер ревизии могут отличаться. Больший номер сборки указывает на более новую версию той же совместимой сборки, а больший номер ревизии указывает на незначительное изменение (возможно, исправление незначительной ошибки) или изменения, внесенные в связи с локализацией.

Рисунок 1. Номер версии сборки состоит из основного номера версии, дополнительного номера версии, номера сборки и номера редакции.

Предоставление номера версии

Компилятор генерирует 1.0.0.0 для номера версии сборки.Если указать основной и дополнительный номера, обнуляются только номера сборки и версии. Например, вы указываете в качестве номера версии следующий атрибут сборки:

Компилятор генерирует 1.2.0.0 для номера версии сборки. Однако вы можете указать * для номеров сборки и версии, например:

Компилятор автоматически генерирует номера сборки и версии. В качестве номера сборки компилятор использует количество дней с 1 января 2000 года по местному времени. В качестве номера версии компилятор использует количество секунд с полуночи по местному времени по модулю 999. В приведенном выше примере возможная версия сборки, сгенерированная компилятором, будет следующей:

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

Компилятор использует для номера версии количество секунд, прошедших с полуночи по местному времени, как описано выше. Как правило, наиболее практичный способ указать номер версии — это явно указать основной и дополнительный номер и позволить компилятору сгенерировать номера сборки и версии:

Разрешение совместимых сборок

GAC может поддерживать несколько версий общей сборки, обеспечивая параллельное выполнение разных версий сборки.

Строгие имена и общие сборки

Как упоминалось ранее, сборка может быть частной или общей. Частная сборка находится в каталоге клиентских сборок, тогда как общая сборка находится в GAC. Хотя частные сборки просты и удобны в использовании, есть два случая, когда вам следует рассмотреть возможность использования общих сборок.

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

Надежное имя сборки

Создание сильного имени

Файл MyCompanyKeys.snk теперь содержит пару ключей (использование .snk для расширения файла ключей является просто соглашением; это может быть любое другое расширение). Чтобы подписать сборку, необходимо связать файл ключей со сборкой с помощью атрибута сборки AssemblyKeyFile:

Теперь, когда компилятор создает серверную сборку, он будет использовать эти ключи шифрования для присвоения ей строгого имени.

Строгое имя и частная версия сборки

  1. Частные сборки только с понятными именами должны быть обратно совместимы.
  2. Частные сборки со строгими именами могут быть несовместимы с предыдущими версиями, так как GAC может содержать более старую совместимую версию.
  3. Даже если частная сборка со строгим именем обратно совместима (по содержанию), если номер версии несовместим, это приведет к ошибке (если в GAC нет более старой совместимой версии).
  4. Модель развертывания частной сборки действительно предназначена для работы только с понятными именами.

Сборки со строгими и понятными именами

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

Установка общей сборки

Другой вариант — использовать утилиту командной строки GACUtil, которая предлагает ряд переключателей. Обычно вы используете GACUtil в программе установки вашего приложения.

Ссылка на общую сборку

Политика привязки пользовательской версии

Администраторы могут сделать это по любой произвольной причине, но обычно они делают это, когда доступна новая и улучшенная версия библиотеки классов, а поставщик библиотеки классов гарантирует обратную совместимость со старой версией. В таком случае администратор хотел бы воспользоваться преимуществами новой версии. Однако политика привязки и разрешения версии по умолчанию всегда будет пытаться загрузить более старую версию сборки. Если новая версия переопределяет частную копию старой версии со строгим именем, то распознаватель сборки выдает исключение, если ему не удается найти старую версию.

Пользовательская политика приложения

Рисунок 5: Папка настроенных сборок. На правой панели отображаются настроенные сборки, а также сведения о том, были ли созданы для этих сборок настраиваемая привязка версий или политики кодовой базы.

Папка Configured Assemblies содержит все сборки, используемые этим приложением, для которых задана определенная политика. Чтобы предоставить пользовательскую политику для сборки, вы должны добавить ее в папку. Щелкните правой кнопкой мыши папку «Настроенные сборки» и выберите «Добавить». для отображения диалогового окна «Настроить сборку» (см. рис. 6).

Рис. 6. Диалоговое окно "Настроить сборку" позволяет выбрать сборку либо из GAC, либо из списка всех сборок, используемых этим приложением.

Вы можете выбрать либо сборку из GAC, либо сборку из списка всех сборок, используемых этим приложением (список создается при чтении манифеста приложения). Обратите внимание, что хотя в списке отображаются все сборки, включая частные, только с понятными именами, нет смысла выбирать их, поскольку распознаватель игнорирует проблемы с версией, когда сборка не имеет строгого имени. Вы можете легко определить, какие сборки имеют строгое имя: сборки со строгим именем будут иметь некоторое значение в столбце PublicKeyToken (см. рис. 7).

Рис. 7. Список зависимых сборок. Обязательно выбирайте только сборки со строгими именами.

Политика привязки пользовательской версии

Рис. 8. Вкладка «Политика привязки» позволяет администраторам указать собственную политику привязки версий.

Пользовательская политика привязки кодовой базы

Рис. 9. Вкладка Codebase позволяет администраторам перенаправлять запросы на загрузку определенной версии в определенные места.

Файл конфигурации приложения

Глобальная пользовательская политика

Файл конфигурации для всего компьютера

Исторически проблемы с версиями были источником серьезных проблем. Ранние попытки технологии компонентов с использованием DLL и функций, экспортируемых из DLL, привели к затруднительному положению, известному как DLL Hell. Типичный сценарий DLL Hell включает два клиентских приложения, скажем, A1.0 и B1.0, каждое из которых использует версию C1.0 компонента в файле mydll.dll.

И A1.0, и B1.0 устанавливают копию mydll.dll в какое-то глобальное расположение, например в системный каталог. При установке версии A1.1 вместе с ней устанавливается версия C1.1 компонента, обеспечивающая новые функциональные возможности в дополнение к функциональным возможностям, определенным в C1.0. Обратите внимание, что mydll.dll может содержать C1.1 и по-прежнему обслуживать как старые, так и новые версии клиентских приложений, поскольку старые клиенты не знают о новых функциях, хотя старые функции по-прежнему поддерживаются.

Двоичная совместимость поддерживается за счет строгого управления порядковыми номерами для экспортируемых функций (источник другого набора проблем, связанных с DLL Hell). Проблема начинается при переустановке приложения B1.0. В рамках установки B1.0 переустанавливается версия C1.0, переопределяющая C1.1. В результате A1.1 не может быть выполнен.

Интересно, что решение проблемы DLL Hell было одной из движущих сил COM. Несмотря на то, что COM широко использует объекты в библиотеках DLL, COM может полностью устранить ад DLL. Тем не менее, COM не является тривиальным для изучения и применения, и, следовательно, иногда его неправильно использовали или злоупотребляли, что приводило к проблемам, подобным аду DLL.

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

Если ваши сценарии развертывания допускают частное использование сборок, используйте их. Частные сборки обеспечивают максимальную гибкость и изоляцию, предоставляя каждому клиенту собственную версию. Если вам нужно обновить несколько клиентов, проще поделиться через GAC. Редко вам придется делать и то, и другое с разными версиями.

Для большинства исполняемых файлов Windows (DLL, EXE. ), версию и другие сведения можно просмотреть на вкладке «Подробности» в «Свойствах» ( Alt + Enter ).

Интересно: есть ли способ сделать это из командной строки? Меня особенно интересует версия продукта, но могут быть полезны и другие вещи.

Желательны следующие свойства в порядке приоритета:

  • принимать путь к exe/dll в качестве параметра
  • выводить на стандартный вывод (чтобы вы могли обрабатывать остальное через канал |)
  • доступно по умолчанию во всех поддерживаемых Windows (XP+)
  • доступно по умолчанию в Windows Vista+
  • доступно по умолчанию в Windows XP
  • можно использовать в коммерческой среде
  • бесплатная лицензия (подобная GPL)
  • портативный (т.е. автономный исполняемый файл, который может сопровождаться DLL)

5 ответов 5

В powershell введите команду "полный путь к исполняемому файлу" | список форматов сделает свое дело. Powershell — это новая командная строка для Vista и более поздних версий Windows, которую можно установить в XP.

У меня есть команда get "$args[0]" | format-list , который я сохранил как aaa.ps1 и назвал powershell -File aaa.ps1 shell32.dll, но ничего не печатает.

хорошо, я этого не знал, он даже возвращает немного больше информации, чем окно свойств. Интересная информация содержится в свойстве FileInfoVersion объекта ApplicationInfo.

Однако у него много полезных опций, все зависит от того, что вы хотите сделать.

Тем не менее, это не бесплатно, но я думаю, что его можно бесплатно получить с помощью Windows SDK.

Вы можете использовать портативный инструмент sigcheck.exe, который является частью Sysinternals Suite, например

Для более старых версий Windows, таких как XP/2k/2003 (они все еще работают в новых), используйте инструмент filever.exe (проверьте прямую ссылку на exedll.info), чтобы получить конкретную информацию о файле, такую ​​как:

  • Платформа, на которой работает файл
  • Версия файла
  • Атрибуты файла
  • Тип файла
  • Язык файла
  • Является ли файл типом доставки или типом отладки
  • Размер файла
  • Дата создания файла
  • Путь к файлу

Еще что следует учитывать:

Отображает информацию о двоичных файлах Common Object File Format (COFF). Вы можете использовать DUMPBIN для проверки объектных файлов COFF, стандартных библиотек объектов COFF, исполняемых файлов и библиотек динамической компоновки (DLL).

binwalk — поиск в указанных файлах исполняемых кодов операций, общих для различных архитектур ЦП. Простой в использовании инструмент для анализа, обратного проектирования и извлечения интересных файлов/данных из двоичных файлов.

Ад DLL

Но если вы думаете, что эта архитектура решила все наши проблемы, вы будете разочарованы. У нас все еще есть проблемы, просто другие.

Проблемы современного ада DLL

Современное приложение зависит от десятков библиотек, которые обычно используются в виде пакетов NuGet. Каждая из этих библиотек зависит от дюжины других библиотек. И каждый из них… ну вы поняли. Повторное использование кода в наши дни настолько просто, что даже простая программа содержит сотни зависимостей.

Учтите, что некоторые из этих зависимостей могут быть общими. Такие библиотеки, как Newtonsoft.Json или Serilog, настолько распространены, что их используют все остальные приложения или библиотеки. Так что же произойдет, если одна из ваших сотен библиотек зависит от другой версии Newtonsoft.Json или Serilog? Вот в чем проблема.

Ваш запускаемый проект ссылается на Newtonsoft.Json версии 8, а библиотека B ссылается на Newtonsoft.Json версии 9. Это может легко привести к конфликту. Вы можете заставить это работать во время выполнения (с переадресацией привязки), но это может привести к всевозможным проблемам. Проблема зависит от того, какая версия загружается. Если это версия 8, то библиотека А может вызвать несуществующий метод, существующий только в версии 9, и дать сбой во время выполнения. И если бы загружалась версия 9, то то же самое могло бы произойти и со стартовым проектом. В этом случае вы, вероятно, могли бы обновить свой стартовый проект, чтобы использовать Newtonsoft.Json версии 9. Но эта же проблема может проявляться более неприятным образом, например так:

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

Возможные решения

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

1. Подгоните версии

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

  • MAJOR увеличивается, когда вы вносите несовместимые изменения API
  • MINOR увеличивается, когда вы добавляете функциональные возможности с обратной совместимостью
  • PATCH увеличивается при исправлении ошибок, совместимых с предыдущими версиями

Не все соблюдают соглашения, но если и соблюдают, то требуется соответствие только основным версиям, а не точной версии. Если два проекта ссылаются на библиотеку с одной и той же основной версией, убедитесь, что в процесс загружена самая старшая из указанных версий этой библиотеки. Это можно сделать с помощью обязательных редиректов (см. далее). Например, если библиотека A ссылается на Newtonsoft.Json версии 8.0.1, а библиотека B ссылается на версию 8.2.1, вам следует загрузить 8.2.1, иначе есть риск, что вызовы методов из библиотеки B не будут выполнены.

Конечно, изменять код библиотеки таким образом не очень рекомендуется. Во-первых, вы больше не будете зависеть от пакета NuGet, что значительно усложнит обновление.

2. Привязка перенаправлений

Мы можем принудительно указать нашему процессу, какую сборку загружать в случае конфликта, используя перенаправления привязки. Чтобы это работало, нам нужно добавить что-то вроде следующего кода в app.config начальной сборки:

assemblyIdentity имя = "Newtonsoft.Json" publicKeyToken = "30ad4fe6b2a6aeed" культура = "нейтральный" / >

В этом примере всякий раз, когда среда выполнения хочет загрузить Newtonsoft.Json версий от 0 до 12, вместо этого она загружает версию 8.0.3. Это не вызовет никаких исключений во время выполнения, если нет вызова метода, которого нет в загруженном Newtonsoft.Json .

Этот метод является самым простым и наиболее распространенным для решения конфликтов версий. На самом деле Visual Studio автоматически (по умолчанию) добавляет переадресацию привязки при добавлении пакета NuGet. Обратите внимание на флажок Автоматически создавать перенаправления привязки в свойствах проекта.

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

Иногда переадресации с привязкой недостаточно. Если одна из библиотек вызывает несуществующий метод или использует параметры, недопустимые в загруженной версии, это приводит к исключению во время выполнения. Поэтому, если вы не можете привести версии в соответствие, а перенаправления привязки недостаточно, есть способы загрузки сборок разных версий параллельно.

3. Загрузка сборок разных версий рядом

Прежде чем приступить к использованию любого из методов, описанных ниже, обязательно ознакомьтесь с приведенными здесь рисками. Библиотека не знает, что другая ее версия живет в том же процессе. Это означает, что любой ресурс, используемый библиотекой, может вызвать всевозможные проблемы. Например, запись в один и тот же файл, использование мьютекса с тем же именем или множество вещей, которые вы не можете предвидеть.

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

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

<р>3.1. Использование события AssemblyResolve — событие AppDomain.CurrentDomain.AssemblyResolve запускается, когда сборка не загружается. Это может произойти, если одна и та же сборка другой версии уже загружена. Вы можете использовать эту возможность, чтобы проигнорировать ошибку и принудительно загрузить другую версию сборки параллельно. Хотя это похоже на взлом, это самый простой способ добиться параллельной загрузки, и он работает как для сборок со строгими именами, так и для сборок без таковых.

3.2. Используйте для загрузки сборок из разных папок. Этот метод требует, чтобы ваши библиотеки имели строгие имена. Вы можете поместить разные версии библиотек в разные папки и указать среде выполнения, какую папку использовать для какой версии.

<р>3.3. Используйте глобальный кэш сборок. Этот метод также требует, чтобы ваши библиотеки имели строгие имена. Вместо того, чтобы ссылаться на библиотеки и копировать их в выходную папку bin, вы можете установить их в GAC. Среда выполнения будет знать, что нужно загружать правильные версии рядом друг с другом.

<р>3.4. Перепакуйте свои библиотеки в новую сборку. Вы можете полностью предотвратить конфликт версий, переименовав библиотеку и ее ссылки. Вы не сможете сделать это вручную из-за того, как CLR загружает сборки, но есть решения, такие как ILMerge и il-repack, которые могут сделать это за вас. Они заботятся о таких проблемах, как строгие имена, и могут объединять сборки и их ссылки в новую целевую сборку с другим именем.

Обзор

Думаю, можно с уверенностью сказать, что в этом вопросе нет ничего слишком простого, но я надеюсь, что смог прояснить ситуацию.

Мы видели, как могут возникать конфликты зависимостей с простыми ссылками на библиотеки. Мы увидели, почему использование перенаправления привязки может быть проблематичным и привести к исключениям во время выполнения. И мы увидели множество способов решения конфликтов версий.

Почти во всех случаях конфликт версий разрешается путем корректировки версий и нескольких переадресаций привязки. На самом деле, поскольку Visual Studio автоматически добавляет эти перенаправления привязок, вы в большинстве случаев даже не узнаете, что у вас возник конфликт. Тем не менее, проблемы как-то умудряются возникать, и мне приходилось использовать все упомянутые решения (ну, кроме 3.2) в тот или иной момент.

Комментарии закрыты.

Подписаться

Присоединяйтесь к списку рассылки и получайте обновления о новых статьях

Иногда вам может потребоваться обновить стороннее программное обеспечение в зависимости от версии определенного файла DLL. Примером может служить обновление ODBC на клиенте на основе версии файла odbcint.dll.

Следующая процедура описывает, как создать пользовательский компонент и комплект обновления, которые проверяют версию определенного файла DLL.

Чтобы создать компонент обновления и комплект обновления для проверки версии DLL

Перейдите к экрану «Администрирование — Siebel Anywhere», а затем к представлению «Список компонентов обновления».

Появится список компонентов обновления

Создайте компонент обновления и укажите значения полей, показанные в следующей таблице.

Имя поля Значение
Имя upgrade_component_name
Тип компонента Программное обеспечение сторонних производителей
Найти Метод Реестр
Найти информацию hkey,subkey_name,value_name
Метод версии FileVersion

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

Если значением реестра является DefaultIcon, то значение value_name должно быть опущено. Это значение в реестре будет указывать на конкретный файл DLL. Например:

После создания пользовательского компонента, как описано в предыдущих шагах этой процедуры, определите комплект обновления, как описано в Главе 4, "Определение комплектов обновления".

При определении комплекта обновления не забудьте выбрать имя пользовательского компонента обновления (созданного на предыдущем шаге), когда появится страница мастера комплекта обновления.

Читайте также: