У нас есть устаревшее приложение VB6, которое использует Crystal Reports XI для создания печатных отчетов. Опыт показывает, что механизм печати Crystal Reports дает сбой, если он обнаруживает неверную версию usp10.dll (библиотека Windows Uniscribe).
Один клиент постоянно испытывает проблемы с печатью на своих компьютерах с Windows 7 (под управлением Windows 7 Enterprise, 32-разрядная версия). Однако у нас есть несколько других клиентов, использующих различные выпуски Windows 7, у которых нет проблем.
На одной из машин, у которой были проблемы с печатью, я заметил, что в папке C:\Program Files\Common Files\Microsoft Shared\Office10\
была более старая версия usp10.dll
(несовместимая с Crystal Reports XI). Я не уверен, какое приложение установило эти файлы, потому что у клиента не установлен Office 2002 (поэтому я предполагаю, что другое приложение установило их). Однако я временно переименовал файл, и наше приложение смогло правильно печатать, поэтому кажется, что наше приложение изначально загружало эту версию файла, что вызывало сбои.
Сбой происходит только в тот момент, когда пользователь пытается распечатать отчет. Наше приложение напрямую зависит от craxdrt.dll (библиотека времени выполнения Crystal Reports ActiveX Designer) и crviewer.dll (библиотека средства просмотра отчетов Crystal ActiveX), и происходит сбой, если мы печатаем непосредственно через craxdrt.dll или через элемент управления Report Viewer.
В прошлом мы решали эту проблему, копируя известную исправную версию usp10.dll в каталог нашего приложения и создавая файл .local для включения перенаправления DLL. На сайте клиента я попробовал это, а также попробовал альтернативный подход - создать папку .local для нашего EXE и поместить туда usp10.dll , но ни один подход не работал машина, к которой я был подключен.
Я заметил, что usp10.dll - это «известная» DLL в Windows (в ней есть запись в HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\KnownDLLs
), но я протестировал наше приложение на другом компьютере с Windows 7 (под управлением Professional Edition, 32-разрядная версия), в которой также была указана библиотека DLL в реестре как известная библиотека DLL, и, используя Dependency Walker , я мог видеть, что перенаправление работает на этом компьютере. Это несколько сбивает с толку, так как документация Microsoft гласит, что известные DLL не могут быть перенаправлены. Кроме того, как я и подразумевал в заголовке вопроса, наш основной EXE-файл не использует файл манифеста (в документации Microsoft указано, что наличие манифеста, встроенного или автономного, отключает перенаправление DLL).
Итак, мой вопрос: есть ли другая причина, по которой перенаправление DLL будет работать на некоторых компьютерах, а не на других, и имеет ли это какое-либо отношение к различиям между Windows 7 и Windows XP? Я рассмотрел вопрос об удалении всего в разделе реестра KnownDLLs
, но поскольку перенаправление работало на машине с таким же набором KnownDLLs
, я не уверен, что это действительно решит проблему, и я не хочу удалить этот ключ, если мне не нужно. У меня еще не было возможности снова подключиться к машине клиента, чтобы запустить Dependency Walker , но я не уверен, что смогу интерпретировать его журналы в любом случае (даже на машине, где он работал Я видел много LoadLibrary вызовов usp10.dll , указывающих на папку, отличную от перенаправленной, но некоторые вызовы были, по-видимому, перенаправлены, поэтому я не уверен, что это значит либо).
EDIT : Я должен был также упомянуть, что на каждом проверенном нами компьютере есть еще одна копия usp10.dll
в папке System32
. Глядя на ответ Криса и в этом блоге Ларри Остермана , объясняющий немного больше о том, как работают известные библиотеки DLL, я понял, что это, вероятно, вообще не учитывает проблему, так как наш программа не загружает копию usp10.dll
, которая находится в папке System32
.
РЕДАКТИРОВАТЬ # 2 : после игры с Dependency Walker еще немного на моей машине для разработки VB6 (Windows XP SP3), где печать всегда работала, я смог найтинекоторая информация.Я профилировал наше приложение в Dependency Walker и настроил его на запись полных имен путей, и похоже, что одна из зависимостей Crystal Reports (другая DLL-библиотека Crystal Reports) пытается загрузить usp10.dll от нескольких (жестко запрограммированных) путей, прежде чем сдаться и просто запросить его по имени файла.Оказывается, он сначала пытается загрузить его из папки Crystal Reports bin
, а затем пытается загрузить из C:\Program Files\Common Files\Microsoft Shared\Office10\usp10.dll
.Если он не может найти его ни в одном месте, он просто запрашивает у Windows usp10.dll
(который захватит тот в System32
).Но даже это не соответствует.Иногда он запрашивает файл в папке Office10
, а затем, кажется, игнорирует тот факт, что он не может найти файл, в то время как в других случаях происходит серия вызовов LoadLibrary , где он выглядит какКод Crystal Reports активно ищет альтернативные копии файла в разных местах.Еще более запутанным является то, что, по крайней мере, один из компонентов Crystal Reports выглядит так, как будто на самом деле имеет зависимость времени загрузки от usp10.dll , поэтому компонент всегда получает копию в System32
.
Я до сих пор не уверен на 100% , почему перенаправление .local
не будет работать в такой ситуации на компьютерах этого клиента, но я думаю, что это частично объясняет, почему у этого конкретного клиента возникают проблемы,поскольку на всех компьютерах с этой проблемой есть папка Office10
с явно несовместимой версией usp10.dll
.
Но, опять же, у меня все еще остается основной вопрос: если эти компонентыищите этот файл в самых разных местах, как я могу гарантировать, что все они будут использовать одну и ту же копию?