Программирование для Windows NT© Александр Фролов, Григорий ФроловТом 27, часть 2, М.: Диалог-МИФИ, 1996, 272 стр. DLL-библиотеки в операционной системе Windows NTВ операционной системе Microsoft Windows версии 3.1 после загрузки DLL-библиотека становилась как бы частью операционной системы. DLL-библиотека является модулем и находится в памяти в единственном экземпляре, содержит сегменты кода и ресурсы, а так же один сегмент данных (рис. 3.3). Можно сказать, что для DLL-библиотеки создается одна копия (instance), состоящая только из сегмента данных, и один модуль, состоящий из кода и ресурсов. Рис. 3.3. Структура DLL-библиотеки в памяти DLL-библиотека, в отличие от приложения, не имеет стека и очереди сообщения. Функции, расположенные в модуле DLL-библиотеки, выполняются в контексте вызвавшей их задачи. При этом они пользуются стеком копии приложения, так как собственного стека в DLL-библиотеке не предусмотрено. Тем не менее, в среде операционной системы Microsoft Windows версии 3.1 функции, расположенные в 16-разрядной DLL-библиотеке, пользуются сегментом данных, принадлежащей этой библиотеке, а не копии приложения. Создавая приложения для операционной системы Microsoft Windows версии 3.1, вы делали DLL-библиотеки для коллективного использования ресурсов или данных, расположенных в сегменте данных библиотеки. Функции, входящие в состав 16-разрядной DLL-библиотеки, могут заказывать блоки памяти с атрибутом GMEM_SHARE. Такой блок памяти не принадлежит ни одному приложению и поэтому не освобождается автоматически при завершении работы приложения. Так как в Windows версии 3.1 все приложения используют общую глобальную память, блоки памяти с атрибутом GMEM_SHARE можно использовать для обмена данными между приложениями. Управлять таким обменом могут, например, функции, расположенные в соответствующей DLL-библиотеке. Когда разные приложения, запущенные в среде операционной системы Microsoft Windows версии 3.1, обращались к одной и той же функции DLL-библиотеки, то они все использовали для этого один и тот же адрес. Это и понятно - так как все приложения работали на одной виртуальной машине, то все они находились в одном адресном пространстве. В операционной системе Microsoft Windows NT каждое приложение работает в рамках отдельного адресного пространства. Поэтому для того чтобы приложение могло вызывать функции из DLL-библиотеки, эта библиотека должна находиться в адресном пространстве приложения. Здесь мы обращаем ваше внимание на первое отличие механизма динамической компоновки в среде Microsoft Windows NT от аналогичного механизма для Microsoft Windows версии 3.1. Отображение страниц DLL-библиотекиВ среде Microsoft Windows NT DLL-библиотека загружается в страницы виртуальной памяти, которые отображаются в адресные пространства всех “заинтересованных” приложений, которым нужны функции из этой библиотеки. При этом используется механизм, аналогичный отображению файлов на память, рассмотренный в первой главе нашей книги. На рис. 3.4 схематически показано отображение кода и данных DLL-библиотеки в адресные пространства двух приложений. Рис. 3.4. Отображение DLL-библиотеки в адресные пространства двух процессов На этом рисунке показано, что в глобальном пуле памяти находится один экземпляр кода DLL-библиотеки, который отображается в адресные пространства приложений (процессов). Что же касается данных DLL-библиотеки, то для каждого приложения в глобальном пуле создается отдельная область. Таким образом, различные приложения не могут в этом случае передавать друг другу данные через общую область данных DLL-библиотеки, как это можно было делать в среде операционной системы Microsoft Windows версии 3.1. Тем не менее, принципиальная возможность создания глобальных областей памяти DLL-библиотеки, доступных разным процессам, существует. Для этого необходимо при редактировании описать область данных DLL-библиотеки как SHARED. Заметим, что одна и та же функция DLL-библиотеки может отображаться на разные адреса в различные адресные пространства приложений. Это же относится к глобальным и статическим переменным DLL-библиотеки - они будут отображаться на разные адреса для различных приложений. Когда первое приложение загрузит DLL-библиотеку в память (явно или неявно), эта библиотека (точнее говоря, страницы памяти, в которые она загружена) будет отображена в адресное прстранство этого приложения. Если теперь другое приложение попытается загрузить ту же самую библиотеку еще раз, то для него будет создано новое отображение тех же самых страниц. На этот раз страницы могут быть отображены уже на другие адреса. Кроме того, для каждой DLL‑библиотеки система ведет счетчик использования (usage count). Содержимое этого счетчика увеличивается при очередной загрузке библиотеки в память и уменьшается при освобождении библиотеки. Когда содержимое счетчика использования DLL-библиотеки станет равным нулю, библиотека будет выгружена из памяти. Обмен данными между приложениями через DLL-библиотекуВ среде операционной системы Microsoft Windows версии 3.1 существовала возможность обмена данными между различными работающими параллельно приложениями через область локальной кучи (local heap) DLL-библиотеки. Эта область находилась в сегменте данных DLL-библиотеки и потому была доступна всем приложениям. Что же касается операционной системы Microsoft Windows NT, то в ее среде DLL-библиотеки не имеют собственных областей данных, а отображаются в адресные пространства приложений, загружающих эти библиотеки. Как результат, приложения не могут получать адреса статических и глобальных переменных и использовать эти переменные для обмена данными - ведь адрес, верный в контексте одного приложения, не будет иметь никакого смысла для другого приложения. Приложение также может сделать попытку изменить содержимое статической или глобальной переменной, с тем чтобы другие приложения могли прочитать новое значение. Однако этот способ передачи данных между приложениями не будет работать. Попытка изменения данных будет зафиксирована операционной сиситемой, которая создаст для этого приложения копию страницы памяти, в которой находится изменившиеся данные, с использованием механизма копирования при записи (copy-on-write). Мы рассказывали об этом механизме в предыдущем томе “Библиотеки системного программиста”. Если по какой-либо причине вы не можете использовать для обмена данными между приложениями файлы, отображаемые на память, можно создать DLL-библиотеку с данными, имеющими атрибут SHARED. Для этого прежде всего вы должны задать имя секции данных, которая будет использована для передачи данных между процессами. Это можно сделать с помощью прагмы транслятора data_seg: #pragma data_seg (“.shar”) После этого в файле определения модуля для DLL-библиотеки необходимо указать атрибуты секции данных, как это показано ниже: SECTIONS .shar READ WRITE SHARED Можно также указать ключ редактору связей: -SECTION:.shar,RWS Строка RWS определяет атрибуты секции: R - READ, W - WRITE, S - SHARED. При обращении к глобальным переменным, расположенным в секции с атрибутом SHARED, процессы должны выполнять взаимную синхронизацию с использованием таких средств, как критические секции, объекты-события, семафоры. |