Динамически компонуемые библиотеки Цель: изучить библиотеки DLL (Dynamic Library Link или динамически подключаемые библиотеки), понять, где, каким образом и когда нужно использовать DLL-файлы. Проблема Пока существовали однозадачные операционные системы, проблема с излишней тратой дискового пространства была единственной. Но как только появились многозадачные операционные системы ( например Windows), сразу возникла другая проблема. Представьте себе ситуацию, когда вы запускаете две программы (программы имеют одинаковые фрагменты кода) одновременно. При старте любой код грузится в оперативную память и только потом выполняется. Таким образом получается, что обе программы загрузят в память один и тот же код. Такая ситуация нежелательна. Решение № 1 Одним из первых решений этой задачи стало использование модульного программирования. Программист пишет определенную часть программы, оформляет ее в виде модуля, а потом просто использует этот модуль в своих программах. В качестве модуля может выступать подпрограмма-процедура, подпрограмма-функция и собственно модуль (Unit). При использовании заранее разработанных и отлаженных модулей не надо каждый раз выдумывать велосипед - добавляете к своей программе определенный модуль и используете когда-то написанный вами или кем-то другим программный код. И до настоящего времени это один из основных технологических приёмов написания программ. Однако с появлением многозадачности программисты и простые пользователи заметили, что эффективность программ стала снижаться. Решение № 2 Идея состоит в том, чтобы не стыковать модули с основной программой, а сохранять их в отдельный файл, и пусть любая программа загружает их по мере надобности. Так появились библиотеки DLL. Эти библиотеки подключаются к программе динамически. В них можно хранить исполняемый код в виде процедур или функций, ресурсы программы, графику или даже видеоролики. В этом случае программа не увеличивается на размер модуля при компиляции, а загружает код из DLL-файла в память, а затем использует его. Если одна программа уже загрузила DLL, то следующая не будет делать этого. Она воспользуется уже загруженной версией. Таким образом, экономится не только место на диске, но и оперативная память. Основная идея: при использовании динамических библиотек в исполняемом файле находится только самое основное, а дополнительные возможности подгружаются по мере надобности из DLL-файлов. Например, когда стартует Word, то загружается только модуль текстового редактора. Когда вы выбрали редактор формул Microsoft Equation или объект WordArt, то Word подгружает из DLL-файла код выбранного объекта и выполняет его. Таким образом, суммарная скорость загрузки уменьшается, причем очень значительно. Еще одно большое преимущество динамических библиотек — при их использовании код программы разбивается на несколько файлов (зависит от количества DLL-файлов). Допустим, что в одной из функций, находящихся в DLL-файле, оказался код с ошибкой. В этом случае не надо обновлять всю программу, а достаточно передать всем пользователям только этот DLL-файл, и программа получит необходимые обновления. Две особенности динамических библиотек: 1. Код из DLL-файла выполняется в том же участке памяти, что и основная программа. Поэтому программа и DLL-код используют один и тот же стек данных, что иногда накладывает свои ограничения. Например, DLL-код не может хранить глобальных переменных. Воспринимайте динамические библиотеки просто как набор процедур и функций, которые могут хранить только локальные переменные. 2. Изначально динамические библиотеки были процедурными. Несмотря на это, программы ActiveX (изначально объектные) могут храниться в файлах с расширением dll и выполняют те же задачи, что и классические динамические библиотеки. Графические программы Существует программа для работы с графикой OpenGL.Она состоит из двух динамических библиотек opengl.dll(opengl32.dll) и glu.dll(glu32.dll). Программа DirectX - это графическая библиотека, которая состоит из файлов DirectDraw, DirectInput, DirectMusic, DirectPlay и т. д. Все это не что иное, как динамически подгружаемые библиотеки. DirectDraw это Ddraw.dll, DirectInput это Dinput.dll, DirectMusic это Dmusic.dll и т. д. Хотя DirectX это не простые библиотеки — это библиотеки, созданные на основе технологии СОМ. Любые «игровые движки» (набор функций для облегчения создания игры определенного жанра с определенными возможностями) выполнены в виде динамически загружаемых библиотек, потому что их использование очень простое и удобное для любого программиста. Выводы: 1. Динамические библиотеки практически ничем не отличаются от ЕХЕ-файлов. Это такой же скомпилированный код, только он не может запускаться самостоятельно, потому что в библиотеке нет точки входа (точки, с которой начинает свое выполнение любая программа). 2. В DLL-файлах хранятся процедуры, функции и различные ресурсы, которые можно вызывать из других программ. 3. Чаще всего динамические библиотеки имеют расширение dll, но можно установить и любое другое расширение или вообще убрать его. 4. Библиотеки имеют свои разновидности, например, драйверы — это то же динамические библиотеки и им принято давать расширение drv. Возможно также использование расширения sys для системных файлов. Так что операционная система не накладывает ограничений на расширения динамических библиотек, главное, чтобы программисту было понятно и удобно работать. 5. Когда одно приложение загружает библиотеку, то она загружается ее в глобальную память, а потом только проецируется в адресное пространство программы. Это значит, что программа будет «видеть» функции библиотеки как свои собственные, хотя они расположены совершенно в отдельном адресном пространстве. 6. Операционная система Windows гарантирует, что в любой момент будет загружена в память только одна версия DLL-файла. Если две программы обращаются к одной и той же библиотеке, то в памяти будет находиться только одна копия DLL-файла. Примечание Библиотеки DLL всегда динамические и создаются они с целью динамической загрузки находящихся в них ресурсов. Но, не смотря на это, многие компиляторы позволяют присоединять код DLL статически. В этом случае при компиляции программы код или данные, находящиеся в DLL-файле, становятся неотъемлемой частью исполняемого файла. Программа и библиотека становятся как единое целое. Это очень удобно, когда библиотека небольшая или вам необходимо, чтобы программа состояла только из одного запускного файла. Здесь динамическая загрузка не подходит, и надеяться на существование библиотеки, на машине клиента нельзя. Такая ситуация может возникнуть, когда вы хотите показать клиенту демонстрационный файл вашей программы и удобно иметь только один запускной файл, а не множество библиотек.