Приложение не работает с DLL-библиотеками VS 2008 SP1, предыдущая версия работает с версиями RTM - PullRequest
37 голосов
/ 12 сентября 2008

После перехода с Visual Studio 6 на Visual Studio 2008 мы использовали файлы MFC90.dll и msvc [pr] 90.dll вместе с файлами манифеста в частной параллельной конфигурации, чтобы не беспокоиться о версиях или установке их в систему.

Pre-SP1, это работало нормально (и все еще отлично работает на наших машинах для разработчиков). Теперь, когда мы провели тестирование после SP1, я выдернул волосы со вчерашнего утра.

Прежде всего, наш установочный скрипт NSIS извлекает файлы dll и манифеста из папки redist. Они больше не были правильными, поскольку приложение все еще ссылается на RTM-версию.

Поэтому я добавил определение для _BIND_TO_CURRENT_VCLIBS_VERSION=1 во все наши проекты, чтобы они использовали DLL-библиотеки SP1 в папке redist (или последующие, когда выйдут новые пакеты обновления). Мне понадобилось несколько часов, чтобы найти это.

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

При запуске приложения по-прежнему появляется следующая ошибка:

Приложение не удалось правильно инициализировать (0xc0150002). Нажмите OK, чтобы закрыть приложение.

Ни в одном из поисков, которые я проводил в Google или Microsoft, не было найдено ничего, касающегося моих конкретных проблем (но с этим сообщением об ошибке возвращаются в 2005 г.).

У кого-нибудь была похожая проблема с SP1?

Параметры:

  • Найдите проблему и исправьте ее, чтобы она работала как надо (предпочтительно)
  • Установить редист
  • выкопать старые библиотеки RTM и файлы манифеста и удалить #define, чтобы использовать текущие. (У меня они есть в более ранней сборке инсталлятора, так как Microsoft удаляет их из вашей папки для перенаправления!)

Редактировать: Я попытался пересобрать с отключенным определением (ссылка на библиотеки RTM), и это работает, пока библиотеки DLL RTM установлены в папке. Если библиотеки SP1 вставлены, появляется следующая ошибка:

c: \ Program Files \ ... \ ... \ X.exe

Это приложение не удалось запустить из-за неправильной конфигурации приложения. Переустановка приложения может решить эту проблему.

Никому больше не приходилось иметь дело с этой проблемой?

Редактировать: Просто ради ухмылки я скачал и запустил vcredist_x86.exe для VS2008SP1 на моей тестовой машине. Это работает. С помощью SP1 DLL. И мое RTM связанное приложение. Но NOT в частном параллельном дистрибутиве, который работал до SP1.

Ответы [ 5 ]

40 голосов
/ 16 сентября 2008

Я сам боролся с этой проблемой на прошлой неделе и теперь считаю себя экспертом;)

Я на 99% уверен, что не все библиотеки DLL и статические библиотеки были перекомпилированы с версией SP1. Вам нужно поставить

#define _BIND_TO_CURRENT_MFC_VERSION 1
#define _BIND_TO_CURRENT_CRT_VERSION 1

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

Есть больше флагов, которые определяют, с какими версиями связываться; это задокументировано http://msdn.microsoft.com/en-us/library/cc664727%28v=vs.90%29.aspx. В качестве альтернативы вышеприведенным строкам вы также можете поставить

#define _BIND_TO_CURRENT_VCLIBS_VERSION 1

, которая будет привязана к последней версии всех библиотек VC (CRT, MFC, ATL, OpenMP).

Затем проверьте, что написано во встроенном манифесте. Загрузите XM Resource Editor: http://www.wilsonc.demon.co.uk/d10resourceeditor.htm. Откройте все библиотеки DLL и exe в вашем решении. Посмотрите под «XP Theme Manifest». Убедитесь, что атрибут 'version' с правой стороны имеет значение '9.0.30729.1'. Если это '9.0.21022', некоторая статическая библиотека извлекает манифест для старой версии.

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

Отличный способ отладки, для каких библиотек не установлены директивы препроцессора: временно измените заголовки платформы, чтобы компиляция остановилась, когда она попытается встроить старый манифест. Откройте C: \ Program Files \ Microsoft Visual Studio 9.0 \ VC \ crt \ include \ crtassem.h. Найдите строку «21022». В этом определении поместите что-то недопустимое (замените «define» на «blehbleh» или около того). Таким образом, когда вы компилируете проект, в котором не установлен флаг препроцессора _BIND_TO_CURRENT_CRT_VERSION, ваша компиляция остановится, и вы поймете, что вам нужно добавить их или убедиться, что он применяется везде.

Также убедитесь, что вы используете Dependency Walker, чтобы знать, какие библиотеки извлекаются. Проще всего установить свежую копию Windows XP без обновлений (только SP2) на виртуальной машине. Таким образом, вы точно знаете, что в папке SxS нет ничего, что использовалось бы вместо предоставленных вами параллельных библиотек.

14 голосов
/ 28 января 2010

Чтобы понять проблему, я думаю, важно понять, что задействованы четыре номера версий :

  • (A) Версия файлов заголовков VC, в которую скомпилирован .exe.
  • (B) Версия файла манифеста, встроенная в раздел ресурсов этого EXE-файла. По умолчанию этот файл манифеста автоматически создается Visual Studio.
  • (C) Версия VD .DLL (часть параллельной сборки), которую вы копируете в тот же каталог, что и .exe.
  • (D) Версия файлов манифеста VC (часть параллельной сборки), которую вы копируете в тот же каталог, что и .exe.

В работе находятся две версии DLL-библиотеки VC 2008:

  • v1: 9.0.21022.8
  • v2: 9.0.30729.4148

Для ясности я буду использовать нотацию v1 / v2. В следующей таблице показан ряд возможных ситуаций:

Situation | .exe (A) | embedded manifest (B) | VC DLLs (C) | VC manifests (D)
-----------------------------------------------------------------------------
1         | v2       | v1                    | v1          | v1         
2         | v2       | v1                    | v2          | v2          
3         | v2       | v1                    | v2          | v1
4         | v2       | v2                    | v2          | v2

Результаты этих ситуаций при запуске .exe в чистой установке Vista SP1:

  • Ситуация 1: отображается всплывающее окно со словами: «Не удалось найти точку входа в процедуру XYZXYZ в библиотеке динамических ссылок».

  • Ситуация 2: кажется, ничего не происходит при запуске .exe, но в «Windows Event Viewer / Application log» регистрируется следующее событие:

    Сбой генерации контекста активации для «C: \ Path \ file.exe». Ошибка в манифесте или в файле политики «C: \ Path \ Microsoft.VC90.CRT.MANIFEST» в строке 4. Идентификатор компонента, обнаруженный в манифесте, не соответствует идентификатору запрошенного компонента. Ссылка: Microsoft.VC90.CRT, processorArchitecture = "x86", publicKeyToken = "1fc8b3b9a1e18e3b", type = "win32", version = "9.0.21022.8". Определение - Microsoft

  • Ситуация 3: кажется, все работает нормально. Это решение remicles2 .

  • Ситуация 4: это как это должно быть сделано . К сожалению, как указывает Роэл, это может быть довольно сложно реализовать.

Теперь моя ситуация (и я думаю, что она такая же, как crashmstr ) - это номер 1. Проблема в том, что Visual Studio по той или иной причине генерирует код клиента (A) для v2, но для по той или иной причине создается файл манифеста v1 (B). Я понятия не имею, где можно настроить версию (A).

Обратите внимание , что все это объяснение все еще находится в контексте частных собраний .

Обновление : наконец-то я начинаю понимать, что происходит. Очевидно, Visual Studio генерирует код клиента (A) для v2 по умолчанию , в отличие от того, что я читал в некоторых блогах Microsoft. Флаг _BIND_TO_CURRENT_VCLIBS_VERSION выбирает только версию в сгенерированном файле манифеста (B), но эта версия будет игнорироваться при запуске приложения.

Заключение

.exe, скомпилированный Visual Studio 2008, по умолчанию ссылается на новейшие версии библиотек VC90. Вы можете использовать флаг _BIND_TO_CURRENT_VCLIBS_VERSION , чтобы контролировать, какая версия библиотек VC90 будет сгенерирована в файле манифеста. Это действительно позволяет избежать ситуации 2, когда вы получаете сообщение об ошибке «манифест не соответствует идентификатору запрошенного компонента». Это также объясняет, почему ситуация 3 работает нормально, поскольку даже без флага _BIND_TO_CURRENT_VCLIBS_VERSION приложение связано с новейшими версиями библиотек VC.

Ситуация еще более странная с открытыми параллельными сборками, где запускался vcredist, помещая библиотеки VC 9.0 в каталог Windows SxS. Даже если в файле манифеста .exe указано, что следует использовать старые версии библиотек DLL (в этом случае флаг _BIND_TO_CURRENT_VCLIBS_VERSION не установлен), Windows по умолчанию игнорирует этот номер версии! Вместо этого Windows будет использовать более новую версию, если она присутствует в системе, за исключением , когда используется «файл конфигурации приложения» .

Я единственный, кто считает, что это сбивает с толку?

Итак в итоге :

  • Для частных сборок используйте флаг _BIND_TO_CURRENT_VCLIBS_VERSION в проекте .exe и всех зависимых .lib проектов.
  • Для публичных сборок это не требуется, поскольку Windows автоматически выберет правильную версию .DLL из каталога SxS.
4 голосов
/ 14 октября 2009

Другим хорошим инструментом для просмотра манифестов exe и dll является Просмотр манифеста , который, как ни странно, не будет работать при чистой установке XP, поскольку it зависит от 9.0.21022.

4 голосов
/ 16 сентября 2008

Я только что вспомнил еще один прием, который я использовал, чтобы выяснить, какие статические библиотеки плохо себя вели: «grep» через статические библиотеки для строки «21022». ОДНАКО, не используйте «нормальные» инструменты grep, такие как wingrep, потому что они не покажут вам эти строки (они думают, что это двоичный файл и ищут необработанную строку, не являющуюся юникодом). Используйте утилиту 'strings' из набора ресурсов (я думаю, теперь на сайте Руссиновича). Это будет работать через двоичные файлы в порядке. Таким образом, вы позволяете этим «строкам» пройти по всему дереву исходного кода и увидите двоичные файлы (библиотеки DLL и статические библиотеки), которые содержат ссылки на неправильный манифест (или на манифест с неверной версией в нем).

2 голосов
/ 14 октября 2009

В качестве третьего варианта вы, вероятно, можете найти библиотеки DLL и манифесты для версии 9.0.21022 в каталоге C: \ WINDOWS \ WinSxS на вашем компьютере разработчика. Если вы можете, тогда вы можете установить свой собственный каталог для переадресации и установить эти файлы вместе с вашим приложением.

В качестве альтернативы, вы можете использовать те 9.0.30729.1, которые поставляются с Visual Studio, и подделать манифест, который вы устанавливаете вместе с вашим приложением, чтобы сообщить, что оно предоставляет библиотеки DLL 9.0.21022, а не 9.0.30729.1. Компоновщик времени выполнения, похоже, не возражает. См. Этот блог , который был чрезвычайно полезен для решения этих проблем, для получения дополнительной информации.

Оба обходных пути устранили проблемы, возникающие при развертывании библиотек DLL в качестве частных сборок с VS2008 Express.

Ответ Роэла - это путь к первому варианту («исправьте это правильно»), но если вы зависите от библиотеки, которая зависит от 9.0.21022 (и, следовательно, ваш манифест перечисляет обе версии), тогда третий вариант может быть единственным способом, если вы не хотите запускать vcredist_x86.exe.

...