Корень проблемы лежит в разделяемой природе DLL и других компонентов Windows, таких, как com
При работе с системой Windows нередко возникает весьма неприятная ситуация, когда несколько прикладных программ, использующих общие компоненты, оказываются не в состоянии работать независимо друг от друга. Встроенные функции защиты файлов (Windows File Protection, WFP), «сосуществующие» (side-by-side, S*S) компоненты и метод перенаправления DLL помогут администраторам избежать путаницы. Вероятно, в данном случае эти три способа исправления ошибок среды Windows 2000 будут полезнее, чем все остальные технологии операционной системы. Благодаря новым функциям Windows 2000 выбраться из «ада DLL» (DLL HELL) гораздо легче.
Дорога в «ад»
DLL и другие совместно используемые компоненты - это библиотеки модулей многократно применяемого программного кода, которые могут подгружаться вызывающими их прикладными программами «на ходу». Однако DLL, элементы управления OLE (OCX) и другие им подобные модули могут вызывать ошибки при размещении нескольких приложений на настольных машинах Windows. Причиной тому - разделяемая природа DLL и других прикладных компонентов Windows, таких, как элементы управления COM. При использовании OCX, компонента COM или DLL на базе Win32 предполагается, что компонент обратно совместим с прежними версиями. При обновлении компонента или библиотеки, которая используется несколькими программами, предполагается, что все программы будут по-прежнему работать корректно.
На самом деле обратная совместимость зачастую отсутствует. В некоторых случаях при первой же попытке задействовать новую версию компонента в зависимой программе возникает ошибка. Положение усугубляется тем, что многие поставщики ПО, в том числе и Microsoft, поставляют вместе с прикладными программами новые версии таких разделяемых компонентов. После установки нового приложения обновляются и совместно используемые компоненты. В результате другие программы при попытке использовать измененные компоненты «зависают». Это и называется «адом DLL».
Отслеживание компонентов
В Windows NT 4.0 избежать подобной ситуации трудно. Во многих случаях нужно отделить определенные программы друг от друга, чтобы не допустить совместного использования ими .dll-файлов и других компонентов. Однако разделение программ ограничивает гибкость Windows и увеличивает общую стоимость владения инфраструктурой на базе NT.
Чтобы отслеживать число программ, зависящих от конкретного компонента, в Windows 2000 и NT 4.0 используется метод подсчета ссылок (refcounts). Для осуществления каждое зависимое приложение должно корректно увеличивать и уменьшать счетчик ссылок при установке и удалении каждого компонента. Не все программы выполняют эту операцию или делают это верно. Счетчики ссылок на разделяемые DLL и другие компоненты хранятся в разделе реестра HKEY_LOCAL_MACHINESOFTWARE MicrosoftWindows CurrentVersionSharedDLLs. Для регистрации совместно используемых COM-компонентов в разделах HKEY_CLASSES_ROOTCLSID и HKEY_CLASSES_ROOTInterface используется их уникальный глобальный идентификатор GUID. Элемент HKEY_CLASSES_ROOTCLSID определяет местонахождение компонента в файловой системе (путь к компоненту обычно хранится в параметре реестра InProcServer32). Чтобы найти конкретный COM-компонент, вызывающая прикладная программа обращается в реестр. Затем программа отыскивает DLL-, EXE- или OCX-компонент, содержащий нужные функции.
Если компонент построен не на базе COM (например, библиотека функций Win32), то в программе используется иная процедура поиска и загрузки нужного файла. Во многих программах работает алгоритм, в соответствии с которым поиск ведется сначала в системной памяти, затем в winntsystem32, затем в каталоге приложения, и наконец, по всем путям, определенным в системе. По умолчанию большинство совместно используемых компонентов покупных и самостоятельно разработанных программ устанавливается в каталоге winntsystem32.
Например, предположим, что куплена и установлена прикладная программа A, при этом в каталоге winntsystem32 на всех рабочих станциях устанавливается модуль comctrl32.ocx версии 1.0. Спустя шесть месяцев устанавливается программа B, вместе с которой поставляется модуль comctrl32.ocx версии 2.0. Программа установки приложения B обнаруживает OCX версии 1.0 и заменяет ее на версию 2.0. Предполагается, что приложение A будет работать с версией 2.0 компонента, но часто они оказываются несовместимыми. Нередко приложение A отказывает и сообщает о несовместимости метода или о том, что не может найти точку входа или перечисляемый тип. Из такого положения может быть два выхода. Можно не устанавливать программы A и B на одной машине или модернизировать программу A, чтобы она работала с компонентом версии 2.0. Иногда выполнить такую модернизацию нелегко, например, если приложение A установлено на 50 000 настольных ПК или компания, разработавшая программу, прекратила свое существование, а исходный текст программы отсутствует. Специалисты Microsoft в Windows 2000 и Windows 98 Second Edition (Win98SE) попытались исправить положение.
Защита данных Windows
В состав Windows 2000 и Win98SE входит WFP - процесс, выполняемый в фоновом режиме на всех серверах и рабочих станциях Windows 2000. WFP следит за системными файлами, установленными операционной системой в каталоге winntsystem32. Если пользователь или программа заменяет защищенный файл модулем другой версии, то WFP незаметно восстанавливает копию удаленного оригинала, которая хранится в кэше (по умолчанию кэш находится в каталоге winntsystem32dllcache). В кэше защищенных файлов хранится несколько совместно используемых компонентов компании Microsoft (например, библиотека базовых классов - mfc.dll, библиотека стандартных элементов управления - comctrl32.dll). Более подробно об утилитах WFP рассказано во врезках «Программа контроля системных файлов» и «Проверка сигнатуры файла».
Чтобы получить сертификат, прикладная программа не должна содержать защищенных компонентов. Благодаря этому требованию авторы приложений не могут распространять различные версии компонентов Microsoft, что может нарушить функционирование зависимых программ. Однако для программы, в которой используются разделяемые компоненты, отличные от предоставляемых Microsoft, или программы с разными версиями разделяемых компонентов Microsoft, отличных от имеющихся в Windows 2000, - WFP будет неэффективна или вообще бесполезна. В этом случае можно использовать другие способы - S*S-компоненты и перенаправление DLL.
S*S-компоненты
В среде Windows 2000 существует несколько подходов к решению проблемы несовместимости DLL. Один из них основан на программных изменениях. Если программисты компании составляли приложения на базе COM или Win32 для собственной вычислительной среды, и в будущем планируется переход на Windows 2000 Professional, то следует подумать об S*S-компоненте. Если необходимо немедленно приступить к работе с существующими приложениями, то лучше воспользоваться методом перенаправления DLL. Программисты, работающие над новым приложением или набором разделяемых модулей для Windows 2000, могут использовать S*S, которые представляют собой изолированные компоненты для конкретной программы. Благодаря изолированности S*S достоинства DLL удается сочетать с преимуществами статически связанных библиотек. На одной машине с установленной Windows 2000 могут сосуществовать разные версии S*S-компонентов. Таким образом, на машине могут одновременно работать разные версии одного разделяемого компонента.
Проектируя S*S-совместимые компоненты Win32 и COM, необходимо помнить, что для некоторых программ потребуются иные версии данного компонента. Вся информация о состоянии компонента (например, о структуре данных, файловых и иных ресурсах компонента) должна быть оформлена как private. Для этого необходимо принять специальные меры при составлении исходного текста и установке программы.
Новому S*S-компоненту нужно дать имя, отличное от имен прежних, S*S-несовместимых версий. Переименование позволит избежать проблем обратной совместимости с компонентами, не относящимися к типу S*S, при установке нового компонента в среде NT 4.0 или другой версии Windows, непригодной для работы с S*S-компонентами.
Необходимо также разделить участки памяти и структуры данных. В Windows 2000 реализован механизм совместного использования памяти несколькими процессами. Разделы памяти представляют собой управляемые объекты памяти, обеспечивающие доступ к разделяемому программному коду в файле на диске или в страничном файле из нескольких приложений. Например, из приложения может быть вызвана функция Win32 API CreateFileMapping() для создания раздела памяти, который будет отображаться на определенный файл или ту область страничного файла, где система хранит разделяемые компоненты. Поскольку в режиме S*S могут одновременно работать несколько версий компонента, не следует использовать для отображения компонентов разделы памяти, доступные более чем одному процессу. Кроме того, компоненты не должны формировать никаких совместно используемых структур данных в памяти; различные версии компонента могут обращаться к этим структурам и затем функционировать некорректно.
В новом компоненте S*S необходимо разделить данные пользователя и данные приложения. Если компонент запоминает данные о пользователе или о приложении, то не следует хранить их в таком месте, где они могут быть заменены данными другой версии компонента. Например, предположим, что проектируется COM-компонент или Win32 DLL для пересылки сообщений электронной почты через Microsoft Exchange Server. Чтобы выполнить эту задачу, DLL сохраняет информацию об имени почтового ящика, через который система будет пересылать почтовые сообщения. Предположим, что система сохранила эти данные о конфигурации в файле в глобальной папке (например, C:winnt). Предположим также, что построена новая версия почтового компонента и в ней изменен формат файла для хранения данных о конфигурации. Старая версия файла будет заменена новой. В результате программы, в которых использовалась старая версия файла, перестанут работать.
Следует также убедиться, что информация о пользователе или о приложении хранится в разделах реестра, предназначенных для данной версии компонента. Например, сведения о конфигурации почтового компонента следует поместить в таком разделе, как HKEY_LOCAL_MACHINE SOFTWAREABCSoftwareMailComponent1.5. В этом случае данные о конфигурации компонентов всех версий хранятся в реестре отдельно.
Трудности в работе с COM-компонентами отличаются от проблем с простыми компонентами на базе Win32. COM-компоненты регистрируются по идентификаторам GUID в HKEY_CLASSES_ ROOT. Чтобы сделать их частными, важно корректно зарегистрировать S*S COM-компоненты. Процедуру регистрации можно в целом разработать при формировании пакета приложения для установки. Путь к файлу компонента (например, DLL, OCX) должен быть относительным. Информация о местоположении COM-компонентов обычно хранится под идентификатором GUID в параметре InProcServer32 реестра, и многие компоненты, саморегистрирующиеся во время установки или при запуске, регистрируют свой абсолютный путь в параметре InProcServer32. Например, если установить саморегистрирующийся компонент mywidget.dll в каталоге C:program filesapplicationA, то в InProc-Server32, скорее всего, будет занесено значение C:winntsystem32mywidget.dll. Такой метод регистрации не позволяет сделать компонент частным, потому что mywidget.dll может быть установлена во множество каталогов при загрузке каждой связанной с ним прикладной программы. Если же указан относительный путь, то связанная с компонентом программа, прочитавшая значение InProc-Server32, чтобы отыскать mywidget.dll, не будет направляться к конкретному экземпляру данной DLL, установленной одним определенным приложением. Упаковывая приложение, которое размещает S*S COM-компоненты, необходимо использовать относительный путь для регистрации S*S COM-компонентов в реестре. Путь будет выглядеть примерно так: HKEY_CLASSES_ROOTCLSID {01c6b350-12c7-11ce-bd31-00aa004bbb1f} InProcServer32=my-widget.dll.
В этом примере любая прикладная программа, использующая mywidget.dll, отыщет версию компонента, сохраненную в каталоге приложения, прежде чем обнаружит компонент другой версии. Специалисты Microsoft рекомендуют учитывать ссылки на GUID всех зарегистрированных S*S COM-объектов. Учитывая ссылки на GUID S*S COM-компонента, можно узнать, сколько программ используют этот GUID; если удалить все программы, то последняя из них удалит GUID компонента из реестра.
При формировании и использовании совместно с компонентами библиотек типов разработчики Microsoft рекомендуют компилировать библиотеки типов не в отдельных .tlb-файлах, а внутри DLL. Библиотеки типов - это списки совместимых с компонентом интерфейсов, позволяющие определить функциональность компонента. S*S-компоненты не работают с внешними файлами библиотек типов, поэтому они не регистрируют эти файлы в реестре, как это делают текущие компоненты (в HKEY_CLASSES_ROOTTypeLib).
Важно помнить о том, что новые S*S-компоненты, устанавливаемые в файловой системе Windows 2000, также необходимо сделать частными. Если компонент поставляется в составе конкретного приложения, то нужно подготовить его к установке в каталоге данной программы. Если один и тот же компонент используется несколькими прикладными программами, то каждая из них должна установить одну и ту же версию файла компонента в свой каталог. Такой метод установки - единственный надежный способ сделать компоненты частными.
Перенаправление DLL
Системные администраторы лишены возможности переделать существующие приложения в соответствии с моделью S*S-компонентов. Однако с помощью метода перенаправления DLL можно подготовить старые программы к работе с частично изолированными разделяемыми компонентами без изменений исходного текста прикладных программ, независимо от того, применяется метод к продуктам сторонних поставщиков или к собственным программам. Перенаправление DLL можно выполнить в два этапа.
Шаг 1. Переустановить приложения таким образом, чтобы все зависимые компоненты находились в каталоге прикладной программы. DLL-перенаправленное приложение содержит разделяемые компоненты, которые могут использоваться другими программами, поэтому такие компоненты следует хранить вместе с приложением, а не в каталоге winntsystem32. Такой подход гарантирует, что компонент, используемый перенаправленным приложением, не будет заменен установленной впоследствии новой версией. Кроме того, можно быть уверенным, что новая версия компонента не заменит ранее установленную версию в winntsystem32.
Шаг 2. Это основной этап перенаправления DLL. В каталоге приложения нужно создать пустой файл с именем изолированного приложения и расширением .local. Например, предположим, что требуется изолировать прикладной исполняемый файл под названием myapp.exe. В том каталоге, где система хранит приложение, следует создать файл нулевой длины с именем myapp.exe.local. Для создания файла можно воспользоваться программой Notepad или командой copy con в DOS. Благодаря наличию в каталоге файла .local, при запуске программы, Windows 2000 будет искать разделяемые компоненты только в каталоге приложения. Информация о пути из параметра InProcServer32 для COM-компонентов, зарегистрированных в HKEY_ CLASSES_ROOTCLSID, берется из файла .local, и компонент загружается из локального каталога приложения.
Метод перенаправления DLL работает не со всеми компонентами. Как и в случае с S*S-компонентами, обязательным требованием является корректная работа изолированных перенаправленных компонентов. Например, если компонент использует разделяемую память или не разрешен одновременный запуск нескольких его экземпляров, то перенаправить приложение, вероятно, не удастся. Чтобы узнать, работает ли метод перенаправления DLL с конкретным приложением, нужно проверить программу в перенаправленном режиме при одновременно работающих в системе других перенаправленных приложениях, использующих версии того же разделяемого компонента.
Поиск зависимых компонентов
Основная трудность при перенаправлении DLL - отыскать зависимые компоненты прикладной программы. Эту задачу легче выполнить с помощью утилиты Dependency Walker (depends.exe), поставляемой в составе пакета Windows 2000 Support Tools (программа установки Support Tools находится в папке support ools на компакт-диске Windows 2000 Pro или Windows 2000 Server) или Microsoft Visual Studio (VS). На Экране 1 показано, как использовать Dependency Walker для поиска компонентов исполняемого файла scan32.exe, составной части программы VirusScan компании Network Associates. В левом верхнем окне показаны все зависимые DLL для файла scan32.exe. При подготовке приложения для перенаправления DLL по этому списку можно проверить, все ли зависимые компоненты установлены в каталоге приложения. Однако необходимо убедиться, что компоненты, устанавливаемые вместе с приложением, принадлежат только этой программе и не относятся к числу разделяемых компонентов Microsoft. Например, WFP защищает основные системные файлы, такие, как mcf40.dll, поэтому их необходимо оставить в каталоге winntsystem32, куда они были установлены системой Windows 2000. (Сведения о других средствах «укрощения» DLL приведены во врезке «Ресурсы для изгнания DLL-демонов».)
Экран 1. Поиск компонентов исполяемого файла. |
Окончательное решение
WFP, S*S-компоненты и перенаправление DLL - вполне подходящие методы борьбы с «адом DLL». Они позволяют выиграть время для интеграции многочисленных приложений на машине Windows 2000. Однако эти способы не решают присущую среде Windows проблему, но лишь позволяют ее обойти. Одновременный запуск нескольких изолированных экземпляров одного разделяемого компонента приводит к нерациональному использованию системных ресурсов. Возможно, пока это не так страшно, но положение может стать угрожающим, если одновременно будут работать пять-шесть экземпляров компонента. В конечном итоге S*S-компоненты и перенаправление DLL не избавят от необходимости модернизации приложений для работы с последними версиями компонентов.
Даррен Мар-Элиа - внештатный редактор журнала Windows NT Magazine. Специалист по архитектуре NT; занимается планированием развертывания сетей NT 4.0 и Windows 2000 в масштабах США. С автором можно связаться по адресу: dmarelia@earthlink.net.
Программа контроля системных файлов
Системные администраторы могут воспользоваться утилитой System File Checker (SFC -- sfc.exe) из пакета Windows File Protection (WFP) для проверки корректности защищенных системных файлов и их замены. SFC также сообщает о файлах, которые должны находиться в папке winntsystem32dllcache, но на самом деле отсутствуют. С утилитой можно работать в интерактивном режиме или запускать ее при загрузке системы.
Прежде чем использовать SFC или любую другую подобную утилиту, необходимо убедиться, что имеющаяся версия утилиты корректна. Если вы работали с предварительной (release candidate) или бета-версией Windows 2000, то рекомендуется переформатировать диск и заново установить Windows 2000, чтобы гарантированно иметь один экземпляр таких исполняемых файлов, как sfc.exe.
При запуске SFC с ключом /scannow утилита немедленно приступает к сканированию и выводит на экран диалоговое окно WFP, показанное на Экране A. В диалоговом окне отображается процесс проверки защищенных файлов. Операцию можно в любой момент остановить, щелкнув на кнопке Cancel диалогового окна. На ноутбуке со 150-мегагерцевым процессором Pentium и 144 Мбайт ОЗУ проверка продолжалась более часа. При необходимости система исправляет файлы в процессе работы.
Экран А. Проверка защищенных файлов. |
Если в папке dllcache нужные защищенные файлы отсутствуют, SFC запрашивает компакт-диск с Windows 2000, как показано на Экране B. Если Windows 2000 была установлена с доступного в данный момент сетевого узла или диска CD-ROM, то сообщение не выводится, поскольку SFC автоматически обращается в сеть или к накопителю CD-ROM за нужными файлами. Обнаружив файлы, SFC копирует их в папку dllcache, где они и хранятся до тех пор, пока не понадобятся системе.
Экран В. Запрос на компакт-диск. |
Для выбора режима работы SFC можно использовать несколько параметров. SFC с параметром /quiet проверяет и заменяет некорректные файлы без вмешательства пользователя. Этот режим применяется при запуске SFC в пакетном файле или из программы автоматизированного управления системой, такой, как Microsoft Systems Management Server (SMS).
Параметр /scanboot используется для запуска SFC в ходе начальной загрузки системы. SFC запускается и выполняет проверку при каждой загрузке. Чтобы ограничиться одной проверкой, нужно использовать параметр /scanonce. Предстоящие проверки можно отменить с помощью параметра /cancel. Параметр /enable служит для возвращения WFP в режим по умолчанию.
С помощью параметра /cachesize задается размер кэша WFP. При запуске SFC с этим ключом необходимо указать размер папки кэша в мегабайтах. В статье Microsoft «Windows File Protection Does Not Reduce Cache Size Automatically» (http://support.microsoft.com/support/ kb/articles/q245/8/21.asp) сказано, что уменьшить размер кэша можно лишь после перезагрузки и выполнения SFC с параметром /purgecache для очистки текущего кэша. В документации описывается, как использовать параметры /scannow, /scanonce, и /scanboot для исправления испорченной папки dllcache.
Кен Спенсер работает в учебном центре 32X Tech, который проводит семинары для профессионалов по предлагаемым корпорацией Microsoft технологиям разработки и SQL Server. С ним можно связаться по адресу: kenspencer@32x.com
Проверка сигнатуры файла
Проверка сигнатуры файла (File Signature Verification, FSV) - часть процесса проверки файлов Windows File Protection (WFP). Файлы из состава Windows 2000 снабжены цифровыми сигнатурами, которые используются WFP и утилитой System File Checker (SFC) для проверки файлов. С помощью инструментария FSV можно также искать файлы, имеющие сигнатуры и не имеющие их, на сервере. Таким образом, FSV позволяет проверить, все ли файлы в системе снабжены цифровыми сигнатурами.
Начать процедуру проверки можно с запуска программы Sigverif из командной строки или диалогового окна Run (выполнить). Из диалогового окна процесс можно запустить немедленно или настроить расширенные параметры FSV, щелкнув на кнопке Advanced. На странице Search, одной из расширенных страниц свойств FSV, можно задать режим поиска системных файлов Windows 2000 (по умолчанию) или других файлов. Если выбран режим поиска других файлов (Look for other files) без цифровой сигнатуры, то можно указать искомые типы файлов и папки, в которых следует вести поиск. На другой расширенной странице свойств, Logging, можно установить параметры для проверки файла регистрации. Результаты поиска FSV можно сохранить в текстовом файле, а программа проверки может заменить или добавить результаты в файл регистрации событий. В журнале регистрации содержатся сведения обо всех неполадках с любыми системными файлами. Файлы рабочих станций и серверов можно собрать в единое общедоступное хранилище для анализа.
Экран А. Результаты проверки сигнатур. |
Чтобы начать процедуру проверки, следует запустить Sigverif и щелкнуть на кнопке Start. На Экране A показаны результаты проверки сервера. В список внесены файлы без цифровых сигнатур. Большинство таких файлов имеют расширения .log и .ini; они не имеют сигнатур, поскольку не относятся к числу исполняемых. Однако исполняемые файлы без сигнатур могут вызывать неисправности в системе. Обнаруженные файлы без сигнатур можно оставить без изменений, удалить или заменить.
Настроив параметры Windows 2000, можно выбрать режим установки новых драйверов в системе. Это важно, поскольку не все драйверы являются частью операционной системы и, следовательно, частью WFP. Например, драйверы графической прикладной программы могут быть приобретены у независимого поставщика. Пользователю операционной системы предоставляется выбор: устанавливать драйверы с сигнатурой или драйверы как с сигнатурой, так и без нее. Функция настройки режима находится в модуле System панели управления. Запустив модуль, нужно щелкнуть на закладке Hardware и кнопке Driver Signing. Если задан режим Ignore, то можно установить любой драйвер. В режиме Warn (принимаемом по умолчанию) разрешается устанавливать любые драйверы, но в процессе установки выдается предупреждение о драйверах без сигнатуры. В режиме Block блокируется установка любых файлов драйверов, не имеющих сигнатуры.
Кен Спенсер
Ресурсы для изгнания DLL-демонов
DLL Universal Problem Solver (DUPS) - набор инструментов для поиска неисправностей в DLL на любой платформе Win32. С помощью DUPS можно проверить систему и проследить историю каждой DLL. В ходе данной операции можно сравнить все DLL системы с набором работоспособных DLL и быстро отыскать и устранить неисправности.
О том, как загрузить DUPS, рассказано в статье «Sample: Using DUPS.exe to Resolve DLL Compatibility Problems» (http://support.microsoft.com/support/ kb/articles/q247/9/57.asp). Более подробная информация о DLL и DUPS содержится в статьях Microsoft «The End of DLL Hell» (http://msdn.microsoft.com/ library/techart/dlldanger1.htm), и «Description of the Windows 2000 File Protection Feature» (http://support.microsoft.com/support/ kb/articles/q222/1/93.asp), и «Files Manu-ally Copied to the DLLCache Folder Are Not Used Until the Next Reboot» (http://support.microsoft.com/support/ kb/articles/q236/9/95.asp).
Кен Спенсер