Работа с библиотеками динамической компоновки (dll)


Содержание

Использование динамических библиотек

Приложения, работающие в ОС Windows состоят из исполняемых файлов и динамических библиотек (Dynamic Link Library, DLL) [4].

Динамические библиотеки представляют собой исполняемые модули, содержащие функции и данные, которые могут быть использованы другими модулями (приложениями или динамическими библиотеками). С использованием динамических библиотек создаются приложения на основе модульного принципа, вследствие чего эти приложения могут быстрее загружаться и проще обновляться. Кроме того, если некоторые приложения используют одну и ту же динамическую библиотеку, то эта DLL загружается в ОП только один раз и доступ к ней разрешается всем заинтересованным в ее использовании приложениям.

В динамических библиотеках можно определить 2 типа функций: внешние (экспортируемые) и внутренние. Экспортируемые функции могут вызываться как из DLL в которой они описаны, так и из других модулей. Внутренние функции могут использоваться только в том модуле, в котором они описаны.

Хотя динамические библиотеки могут экспортировать данные, в основном данные, описанные в DLL используются функциями, которые описаны в этой же самой DLL. Однако ничто не запрещает другим модулям считывать или записывать данные, описанные в какой — либо динамической библиотеке.

Набор API-функций, с помощью которых пользовательское приложение взаимодействует с операционной системой, реализован как набор динамических библиотек, поэтому все приложения Windows используют динамические библиотеки.

Динамическое связывание позволяет включать в модули только информацию об экспортируемой в момент загрузки или во время выполнения программы функции DLL. Существует 2 метода вызова функции из DLL.

1. Динамическое связывание во время загрузки (Load-Time Dynamic Linking). В этом случае модуль осуществляет явный вызов экспортируемой функции так, будто она является его локальной функцией. Этот способ требует наличия библиотеки импорта, связанной с DLL содержащей экспортируемые функции, которая обеспечивает ОС информацией, необходимой для загрузки этой DLL и расположением экспортируемых функций внутри DLL.

2. Динамическое связывание во время выполнения программы (Run-Time Dynamic Linking). В этом случае, вызывающее приложение должно использовать специальные API-функции для загрузки DLL, выгрузки DLL и получения адреса экспортируемой функции. Самостоятельное получение адреса экспортируемой функции приводит к тому, что нет необходимости создавать библиотеку импорта.

Каждый процесс, который загружает DLL, отображает ее на свое собственное виртуальное адресное пространство, после чего он может использовать экспортируемые DLL функции.

Для каждой загруженной DLL ОС создает счетчик обращений. Когда процесс загружает DLL, счетчик обращений увеличивается на 1, когда процесс завершается или когда счетчик обращений становится равным 0 (только для динамического связывания во время выполнения программы) — динамическая библиотека выгружается из виртуального адресного пространства процесса.

Как и другая функция, экспортируемая DLL функция выполняется в контексте того потока, который ее вызвал.

Как уже говорилось, динамические библиотеки представляют собой исполняемые модули, содержащие функции и данные, т.е. фактически — динамические библиотеки не отличаются от обычных программ. Разница заключается лишь в том, что функции, определенные в динамических библиотеках могут вызываться другими программными модулями. Многие среды разработки предоставляют шаблон для создания динамической библиотеки.

Файлы с исходным кодом DLL содержат экспортируемые функции и данные, внутренние функции и данные, и дополнительно процедуру входа DLL. Процедура входа может использоваться для инициализации переменных, очистки необходимой для работы области памяти и т.п.

Для выделения экспортируемых функций, в тексте программы DLL за процедурой, вызываемой из другого модуля, необходимо указать ключевое слово EXPORT (если предполагается транслировать этот модуль с помощью пакета MASM) или объявить эту процедуру как PUBLIC (если предполагается транслировать этот модуль с помощью пакета TASM). Если же используется какая-либо среда разработки, то как правило, создание DLL осуществляется на основе шаблона.

Использование динамически связываемых во время загрузки DLL можно наблюдать в приложении А на примере API-функций.

Для использования динамически связываемых во время выполнения DLL используются следующие API-функции:

LoadLibrary —для загрузки DLL в виртуальное пространство вызывающего процесса и получения описателя (дескриптора) данной библиотеки;

GetProcAddress— для получения адреса процедуры, находящейся в динамической библотеке.

После того как работа динамической библиотеки завершена, её можно выгрузить (если конечно больше ни один из модулей эту DLL не использует), вызвав функцию FreeLibrary.

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Для студента самое главное не сдать экзамен, а вовремя вспомнить про него. 10040 — | 7504 — или читать все.

188.64.174.135 © studopedia.ru Не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования. Есть нарушение авторского права? Напишите нам | Обратная связь.

Отключите adBlock!
и обновите страницу (F5)

очень нужно

Портал о домашнем оборудовании

Иногда при запуске какой-либо программы появляется сообщение, что не найден файл *.dll (например, VCompLib.dll) или *.ocx (например, seon.ocx). При этом программа, естественно, не запускается.

Сообщения об ошибках могут быть разные (это зависит в основном от того, на каком языке написана программа), например: «Component «MSCOMM32.OCX» not correctly registered: file is missing or invalid» , или «Приложению не удалось запуститься, поскольку MSVBVM50.DLL не был найден. Повторная установка приложения может исправить эту проблему» , или «Runtime DLL/OCX File error» . При этом в Windows Vista дополнительно появится окно Помощника по совместимости программ с сообщением Эта программа требует отсутствующий компонент Windows .

· DLL (от англ. Dynamic-L ink L ibrary – динамически подключаемая библиотека) – понятие операционной системы Microsoft Windows ; динамическая библиотека, позволяющая многократное применение различными программнымиприложениями. K DLL иногда причисляют также элементы управления ActiveX и . В мире UNIX аналогичные функции выполняют так называемые shared objects («разделяемые объекты»). Формат файлов *.dll придерживается тех жесоглашений, что и формат исполняемых файлов *.exe , сочетая код, таблицы и ресурсы.

·ActiveX – название группы технологий, разработанных Microsoft для программирования компонентных объектных приложений на основе модели COM .

·COM (сокр. от англ. Component Object Model ) – модель компонентных объектов Microsoft , стандартный механизм, включающий интерфейсы, с помощью которых одни объекты предоставляют свои сервисы другим; являетсяосновой многих объектных технологий, в том числе OLE и ActiveX ).

·OLE (сокр. от англ. Object Linking and Embedding ) – общее название (до 1996 г.) группы объектно-ориентированных технологий Microsoft на основе COM (OLE 1, OLE 2, OLE automation , OLE Database и др.).

· ActiveX control – управляющий элемент ActiveX ; введенное в 1996 г. Microsoft новое название независимых программируемых компонентов, ранее называемых OLE controls , OCXs , OLE custom controls ; в отличие от последнихпозволяют работать с Internet .

· OCX (сокр. от англ. OLE Custom eXtension ) – перемещаемые элементы управления, OLE custom control , OLE control . можно сказать, что файлы *.ocx – это элементы управления ActiveX , выполняющие примерно те жефункции, что и файлы *.dll .

· OLE custom control – специализированный управляющий элемент OLE , OLE control .

·OLE control – управляющие элементы OLE , программируемые компоненты-приложения с интерфейсом на базе OLE , позволяющим легко включать их в другие приложения; c 1996 г. называются ActiveX control . Синонимы: OCX , OLEcustom control .

Способы решения проблемы

Если возникают ошибки, связанные с файлами *.dll и *.ocx , необходимо:

1. Переустановить программу.

2. Если переустановка программы не помогает, нужно проверить наличие в системе требуемых файлов. Файлы *.dll и *.ocx , как правило, должны быть расположены в папке \WINDOWS\system32 (реже – в каталоге конкретной программы). Если файлы присутствуют, нужно их.

Если требуемых файлов нет, найдите их в Интернете, скачайте и скопируйте в папку \WINDOWS\system32 и в каталог программы. Теперь нужно их.

При регистрации файлов *.dll и *.ocx происходит их запись в Реестр Windows (это можно сделать и вручную). При этом в ветке создаётся параметр REG_DWORD , например C:\Program Files\InterVideo\Common\Bin\StorageTools.dll или C:\WINDOWS\System32\MSCOMCTL.OCX, со значением 1 .

Регистрация файлов *.dll и *.ocx производится с помощью сервера регистрации regsvr32.exe (дисковый адрес которого – C:\WINDOWS\system32).

Рассмотрим способы регистрации:

1. Нажмите Пуск – Выполнить… – Запуск программы – regsvr32 имя_файла – OK .

2. Нажмите Пуск – Выполнить… – Запуск программы – cmd – OK . Запустится интерпретатор команд cmd.exe , после приглашения системы C:\Documents and Settings\Имя_пользователя> введите regsvr32 имя_файла , например, regsvr32 seon.ocx.

3. Если вы пользуетесь файловым менеджером Total Commander , то можно выполнить регистрацию файлов *.dll и *.ocx с помощью командной строки Total Commander .

Использование команды regsvr32 :

/u – отменяет регистрацию DLL ;

/s – «тихий» режим – окна сообщений не отображаются;

Одни из самых частых ошибок на Windows – это ошибки с DLL библиотеками. Важно знать, как их можно исправить без переустановки ОС.

Windows выдает ошибку с DLL файлом и вы не знаете, что делать? Не переживайте, у вас есть минимум 3 варианта, как устранить любую неполадку подобного характера. Системные документы отвечают за стабильную работу не только самой ОС, но и сторонних программ, так что будет нелишним узнать, как устранить все проблемы

Файлы, имеющие расширение.DLL — это системные файлы, которые используются как Windows, так и сторонними программами. Файлы с таким разрешением часто являются причиной проблем, но система сама предупреждает о них. Если какой-то файл неисправен, то вы увидите сообщение об ошибке, подобное этому:

Когда вы увидели подобное сообщение, нужно обратить внимание, на какой файл ссылается окно. Лучше всего не просто запомнить, но и записать название этого файла. Проблемы с ними хороши тем, что система сама оповещает вас, где искать корень проблемы.

Как исправить ошибки

Есть три способа, как устранить:

  • Восстановить систему;
  • Перезаписать необходимый файл;
  • Использовать универсальные программы;

Восстановление системы – это кардинальный метод, который лучше не применять, если у вас всего 1 ошибка. Этот способ хорош лишь в случае, если у вас массовые неполадки, и система работает крайне нестабильно. Чтобы вы могли восстановить систему вам нужно заранее создать точку восстановления, либо иметь резервную копию всей ОС. Если вы читаете этот материал еще в тот день, когда у вас нет ни одной проблемы, то рекомендуем создать резервную копию или точку восстановления прямо сейчас. Это можно сделать с помощью специальных программ или же просто используйте стандартный функционал вашей операционной системы.

Перезапись необходимого файла – это идеальный вариант, если у вас всего лишь одна. В этом случае вам нужно найти необходимую библиотеку в сети Интернет и перезаписать только ее. Когда будете искать библиотеку, заодно уточните, в каком разделе на компьютере она находится. Также не забудьте, что файлы различаются в зависимости от разрядности ОС. Если у вас Windows 32 bit, то и библиотека вам нужна x32, аналогично поступаем и с Windows 64 бита, туда записываем только 64-ех битные библиотеки.

Третий способ – использование специализированных программ, самый простой. Например, вы можете использовать , но есть и другие утилиты. Подобные программы могут проанализировать ваше устройство, найти все и автоматически их устранить. Рекомендуем использовать только бесплатные варианты программ, так как платные аналоги редко чем отличаются. Автоматическое устранение возможно лишь в том случае, если ваши трудности не критические и система в целом продолжает работать корректно.

Популярные проблемы

Есть несколько проблемных DLL библиотек, которые чаще остальных становятся причиной проблем. К таким библиотекам можно смело отнести следующие:

Все эти проблемы связаны с пакетом DirectX. Чтобы их устранить достаточно скачать и переустановить пакет. В результате вы устраните подобные трудности на своем компьютере на Windows. Ниже представлен еще один способ, если ничего из этой статьи вам не помогло:

Файлы формата DLL открываются специальными программами. Существует 2 типа форматов DLL, каждый из которых открывается разными программами. Чтобы открыть нужный тип формата, изучите описания файлов и скачайте одну из предложенных программ.

Чем открыть файл в формате DLL

Найти и установить любую недостающую или поврежденную DLL библиотеку поможет программа HELPER.DLL .

В файлах формата DLL содержатся настройки ссылки на различные ресурсы, используемые программой, например, иконки. DLL предназначены исключительно для ОС Windows. На других операционных системах открыть такие файлы можно только с помощью эмуляторов (исключением являются кроссплатформенные приложения для Mac OS). Нужно помнить, что современные программы не поддерживают файлы для 16-ти битной архитектуры.

Меры предосторожности

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

Программы для открытия файлов DLL

Просмотр исходного кода

Одним из самых распространенных способов, чтобы просмотреть расширение Dll, является . Программа имеет встроенные функции декомпиляции некоторых файлов, поэтому можно заниматься отладкой dll, а главное, она полностью бесплатна. Разумеется, гарантировать корректное отображение кода для всех файлов невозможно.

В качестве альтернативы можно использовать декомпилятор dotPeek . Он также бесплатен, однако способен работать исключительно с программами, написанными на C#.

Настройка интерфейса программы

Для этой цели лучше всего подходит . С помощью данной программы можно легко сменить иконки, диалоги или установить собственную анимацию. К сожалению, программа является платной даже для некоммерческого использования. Следует обратить внимание, что могут возникнуть проблемы с файлами больших размеров (около 1 ГБ и более).

Самым простым способом является использование Visual Studio от Microsoft. Это довольно функциональный инструмент, в число возможностей которого входит отладка программы, но поможет он только в случае, если на файле нет защиты.

Если же нужно просто скачать DLL взамен битого файла (или отсутствует Dll), то здесь поможет DLL-helper — полностью бесплатная программа.

Динамические web-страницы

Существует и другой формат DLL — файлы, генерирующие код для сайтов. Такие библиотеки можно открыть в любой удобной среде разработки, например, Visual Studio . Протестировать их в действии поможет браузер. Лучше использовать последние версии популярных обозревателей, в противном случае файл может отображаться некорректно.

Веб-страница, автоматически создающаяся во время доступа пользователя. Может объединять серверные сценарии, такие как Perl или , создающие -код для веб-страниц.

Веб-страницы в файлах расширения DLL чаще всего хранятся на веб-серверах Microsoft IIS. Расширение DLL должно отображаться на соответствующем механизме создания сценариев сервера для корректной обработки страницы.

Файл компилированной библиотеки, содержащий набор процедур и/или драйверов, на которые ссылается и которые выполняются программой. Позволяет различным программам получать доступ к общедоступным системным функциям посредством стандартных библиотек. Может динамически связываться в программе во время ее работы.

Многие файлы DLL(читается ДЛЛ) предоставляются операционной системой Windows, другие входят в состав программ Windows. Они также предоставляют различные программные функции, такие как соединение с внешними устройствами и входным и выходным сигналом жесткого диска. На них также могут ссылаться кросс-платформенные приложения для Mac.

Примечание: удаление или изменение содержимого файла DLL может стать причиной ошибок в работе программы, которая ссылается на файл. Поэтому файлы DLL не стоит открывать или редактировать.

Библиотеки динамических ссылок (DLL) похожи на EXE, но они не являются непосредственно исполняемыми. Они похожи на файлы.so в Linux/Unix. Другими словами, DLL — это реализация разделяемых библиотек MS.

DLL файлы похожи на EXE, что сам формат файла тот же. И EXE, и DLL основаны на формате Portable Executable (PE). DLL могут также содержать COM-компоненты и библиотеки.NET.

Что содержит DLL?

DLL содержит функции, классы, переменные, пользовательские интерфейсы и ресурсы (такие как значки, изображения, файлы. ), которые использует EXE или другая библиотека.

Практически во всех операционных системах существует 2 типа библиотек. Статические библиотеки и динамические библиотеки. В Windows расширения файлов следующие: Статические библиотеки (.lib) и динамические библиотеки (.dll). Основное отличие состоит в том, что статические библиотеки связаны с исполняемым файлом во время компиляции; тогда как динамически связанные библиотеки не связаны до времени выполнения.

Подробнее о статических и динамических библиотеках:

Обычно вы не видите статические библиотеки, хотя на вашем компьютере, потому что статическая библиотека встроена непосредственно внутри модуля (EXE или DLL). Динамическая библиотека представляет собой автономный файл.

DLL может быть изменена в любое время и загружается только во время выполнения, когда EXE явно загружает DLL. Статическая библиотека не может быть изменена после ее компиляции в EXE. DLL можно обновлять индивидуально без обновления самого EXE.

Программа загружает DLL при запуске через Win32 API LoadLibrary или когда это зависимость от другой DLL. Программа использует GetProcAddress для загрузки функции или LoadResource для загрузки ресурса.

DLL файлы — это двоичные файлы, которые могут содержать исполняемый код и ресурсы, такие как изображения и т.д. В отличие от приложений, они не могут выполняться напрямую, но приложение загружает их по мере необходимости (или сразу во время запуска).

Насколько они важны?

Большинство приложений загружают файлы DLL, которые они требуют при запуске. Если какой-либо из них не найден, система вообще не сможет запустить процесс.

DLL файлы могут потребовать другие DLL файлы

Точно так же, как для приложения требуется DLL файл, DLL файл может зависеть от других файлов DLL. Если один из этих DLL файлов в цепочке зависимостей не найден, приложение не загружается. Это легко отлаживается с помощью любых инструментов зависимостей зависимостей, таких как Dependency Walker .

Их так много в системных папках


Большая часть функциональных возможностей системы представлена ​​пользовательской программе в виде файлов DLL, поскольку они являются стандартной формой совместного использования кода/ресурсов. Каждая функциональность хранится отдельно в разных DLL файлах, поэтому загружаются только необходимые файлы DLL и, следовательно, уменьшаются ограничения памяти в системе.

Установленные приложения также используют файлы DLL

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

Однако иногда обновления системы часто прерывают другие программы, когда существует несоответствие версии между совместно используемыми файлами DLL и требуемой программой. Системные контрольные точки и кеш-память DLL и т.д. Были инициативами M $для решения этой проблемы. Платформа.NET может не столкнуться с этой проблемой вообще.

Как мы узнаем, что внутри DLL файла?

Вы должны использовать внешний инструмент, например DUMPBIN или Dependency Walker, который не только покажет, какие публично видимые функции (известные как экспорт) внутри DLL файлов, а также какие другие DLL файлы, которые он требует, и которые экспортируют из этих DLL файлов, этот файл DLL зависит от.

Как мы их создаем/используем?

Обратитесь к документации по программному обеспечению от вашего поставщика. Для С++ обратитесь к LoadLibrary в MSDN.

Предположим, вы создаете исполняемый файл, который использует некоторые функции, найденные в библиотеке.

Если используемая библиотека статическая , компоновщик скопирует объектный код для этих функций непосредственно из библиотеки и вставляет их в исполняемый файл.

Теперь, если этот исполняемый файл запущен, он имеет все, что ему нужно, поэтому исполняемый загрузчик просто загружает его в память и запускает его.

Если библиотека динамическая , компоновщик не будет вставлять объектный код, а скорее вставляет заглушку, которая в основном говорит, что эта функция находится в этой DLL в этом месте.

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

Чтобы увидеть это в действии, удалите или переименуйте DLL и посмотрите, как загрузчик сообщит о недостающей ошибке DLL при попытке запустить исполняемый файл.

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

Одно последнее замечание, если вы не подключаетесь к DLL, тогда никакие заглушки не будут вставлены компоновщиком, но Windows по-прежнему предоставляет API GetProcAddress , который позволяет загрузить выполнение DLL после того, как исполняемый файл запущен.

Файлы DLL содержат Таблица экспорта , которая представляет собой список символов, которые могут быть просмотрены вызывающей программой. Символы обычно являются функциями с конвенция вызова C (__ stcall). Таблица экспорта также содержит адрес функции.

С помощью этой информации вызывающая программа может затем вызывать функции внутри DLL, даже если у нее не было доступа к DLL во время компиляции.

DLL (библиотеки динамических ссылок) и SL (разделяемые библиотеки, эквивалентные в UNIX) — это просто библиотеки исполняемого кода, которые могут быть динамически связаны с исполняемым файлом во время загрузки.

Статические библиотеки вставляются в исполняемый файл во время компиляции и фиксируются с этой точки. Они увеличивают размер исполняемого файла и не могут быть разделены.

Динамические библиотеки имеют следующие преимущества:

1/Они загружаются во время выполнения, а не компилируются, поэтому их можно обновлять независимо от исполняемого файла (все эти причудливые окна и диалоговые окна, которые вы видите в Windows, поступают из DLL, поэтому внешний вид вашего приложения может измените, не переписывая его).

2/Поскольку они независимы, код можно разделить на несколько исполняемых файлов — это экономит память, поскольку, если вы используете 100 приложений с одной DLL, в памяти может быть только одна копия DLL.

Их основным недостатком является преимущество # 1 — изменение библиотеки DLL независимо от приложения может привести к тому, что ваше приложение перестанет работать или начнет вести себя причудливо. Версии DLL, как правило, не очень хорошо управляются под Windows, и это приводит к причудливому названию «DLL Hell».

Часто задаваемые вопросы

  1. Откройте zip-файл, скачанный с сайт.
  2. Извлеките DLL-файл в любое место на компьютере.
    • Далее мы советуем вам поместить файл в папку той программы, которая запрашивает данный файл. Убедитесь, что вы используете 32-разрядный формат DLL-файла для 32-разрядной программы, а 64-разрядный формат DLL-файла для 64-разрядной программы, иначе может возникнуть ошибка 0xc000007b.
  3. Если вышеописанные действия не решат вашу проблему, поместите файл в системную папку. По умолчанию эта папка находится здесь:
    • C:\Windows\System (Windows 95/98/Me),
      C:\WINNT\System32 (Windows NT/2000), or
      C:\Windows\System32 (Windows XP, Vista, 7, 8, 8.1, 10).
  4. В 64-разрядной версии Windows папка для 32-разрядных DLL-файлов по умолчанию расположена здесь:

C:\Windows\SysWOW64\ , а для 64-разрядных DLL-файлов
C:\Windows\System32\ .

Обязательно перезапишите все существующие файлы (но сохраните резервную копию оригинального файла).

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

Для 32-разрядных DLL-файлов в 32-разрядных версиях Windows и для 64-разрядных DLL-файлов в 64-разрядных Windows:

  1. Откройте командную строку с повышенными правами.
    • Для этого нажмите Пуск, Все программы, выберите Стандартные, кликните правой кнопкой мышки по Командной Строке, далее нажмите «Запуск от имени администратора».
    • Если вас просят ввести пароль администратора или подтвердить, то введите пароль или нажмите «Разрешить».
  2. Далее введите regsvr32 «filename».dll и нажмите Enter.

Занесение в реестр 32-разрядных DLL-файлов в 64-разрядной версии Windows:

  1. Откройте командную строку с повышенными правами, выполнив вышеописанные действия.
    • cd c:\windows\syswow64\
  2. Далее введите следующее и нажмите Enter:
    • regsvr32 c:\windows\syswow64\»filename».dll

DLL файлы это динамические библиотеки, которыми пользуется множество программ на вашем ПК. В момент удаления или обновления одной из программ с ПК может получится так, что ранее установленные в операционной системе файлы DLL могут удалиться по ошибке. Кроме такой ситуации очень часто система не может обнаружить DLL из-за вирусов, нелицензионного программного обеспечения, которые безусловно накладывают негативный след от своего пребывания на компьютере.

Очень часто файлы DLL пропадают из-за разрыва связей программы и операционной системы в случаях, когда пользватель в ручном режиме переносит программу из одной папки в другую. Только автоматические и системные средства удаления и установки программ на ПК могут обеспечить максимально комфортное использование компьютера и операционной системы.

DLL (англ. Dynamic-link library) — динамическая библиотека

DLL (англ. Dynamic-link library) — понятие операционной системы Microsoft Windows, динамическая библиотека, позволяющая многократное применение различными программными приложениями, понятие операционной системы Microsoft Windows. K DLL относятся также элементы управления ActiveX и драйверы.

Формат файлов DLL придерживается тех же соглашений, что и формат исполняемых файлов EXE, сочетая коды, таблицы и ресурсы.

Цели введения DLL

Первоначально предполагалось, что введение DLL позволит эффективно организовать память и дисковое пространство, используя только одну инстанцию библиотечных модулей для многих приложений. Это было особенно важно для ранних версий Microsoft Windows с жёсткими ограничениями по памяти.

Далее, предполагалось улучшить эффективность разработок и использования системных средств за счёт модульности. Замена DLL-программ с одной версии на другую должна была позволить независимо наращивать систему, не затрагивая приложений. Кроме того библиотеки DLL могли использоваться разнотипными приложениями — например, Microsoft Office, Microsoft Visual Studio и т.п.

В дальнейшем идея модульности выросла в концепцию ActiveX-контролей.

Фактически полных преимуществ от внедрения DLL получить не удалось по причине явления, называемого DLL hell (DLL-евский кошмар). DLL hell возникает, когда несколько приложений требуют одновременно различных версий DLL-библиотек по причине их неполной совместимости, что приводит к серьёзным конфликтам. Когда система выросла до определённых размеров, количество DLL стало превышать многие тысячи, не все из них обладали полной надёжностью и совместимостью, и конфликты типа DLL hell стали возникать очень часто, резко понижая общую надёжность системы. Поздние версии Microsoft Windows стали разрешать параллельное использование разных версий DLL, что свело на нет преимущества изначального принципа модульности.

Материал из справочник исследователя программ. Работа с библиотеками динамической компоновки (DLL)

Рад видеть вас на своём блоге!

Нашли у себя в компьютере DLL файлы и понятия не имеете, что это такое? Я поделюсь с вами информацией. Без них большинство программ и операционная система в целом не смогут функционировать. Хотите знать больше? Не пропустите мою статью.

Разъяснение

Данная аббревиатура расшифровывается как «Dynamic Link Library», а на нашем языке — «библиотека динамической компоновки» или чаще как «динамически подключаемая библиотека». Она по умолчанию устанавливается в ОС Windows, а раньше ещё и в IBM OS/2, пока она не прекратила своё существование. Библиотека предназначена для многократного использования различным программным обеспечением.

DLL содержит в себе важные сведения: о конфигурации системы, совместимости устройств, командах для их корректной работы и пр. Всё это хранится в файлах одноимённого расширения либо.drv для нескольких системных драйверов, .cpl — для файлов панели управления или в.ocx, если речь идёт о библиотеках содержащих фреймворк ActiveX.

Объекты.dll включают в себя коды и данные, которые могут использоваться одновременно несколькими программами. Своим содержимым они похожи на тип файлов EXE. Кстати, у них даже одинаковый формат: Portable Executable (PE) для 32-х и 64-х битных приложений Windows, и New Executable (NE) для 16-битных.

Многие устанавливаемые нами программы уже имеют в своём наборе такие файлы. В противном случае они пользуются теми, которые есть в операционке.

Динамические библиотеки на практике

В теории вроде бы всё ясно. Но чтобы понять суть предмета нашей беседы, необходимо увидеть его с практической стороны. Без него проги не могут работать, потому что не знают, как это делать.

Вот вам элементарный пример. Чтобы на чистом листе в Office Word начали появляться вводимые вами символы, нужны компоненты библиотеки, потому что сама по себе ОС не в курсе, что значит та или иная нажатая вами клавиша.

Даже когда вы просто включаете компьютер и ещё не успели ничего сделать, библиотека уже активно действует: показала вам время и дату, открыла программы в автозапуске, выстроила оформление рабочего стола, проштудировала сведения о конфигурации операционки и т. п. Вдобавок, как система общаться с мышью, клавиатурой, принтером и другим оборудованием, тоже объясняет ДЛЛ.

Преимущества DLL

Для чего предназначены динамические библиотеки? Они создавались для того, чтобы:

Ад для библиотек

В полной мере реализовать описанные выше преимущества всё-таки не удалось. Дело в том, что ПО может одновременно потребовать не полностью совместимые версии библиотек. Из-за этого случаются сбои в его работе. Вдобавок вследствие конфликтов снижается надёжность ОС в целом. Такое явление называется «DLL hell» (если кто не знает, то последнее слово переводится как «ад»).

Как это видит пользователь?

Предположим, вы никогда не обновляли на своём компьютере эти библиотеки и установили игру, выпущенную лет 5 назад. Она работает у вас нормально. Затем вы обнаружили, что недавно вышла последняя часть игры, и инсталлировали её тоже.

Однако вторая уже отказывается запускаться. Своё неповиновение она сопроводила сообщением, мол, ошибка DLL, отсутствует файл. Это значит, что имеющиеся на вашем компе компоненты, необходимые для её запуска, не работают или вовсе отсутствуют.

Такое может быть из-за неправильного указания разрядности или версии системы в процессе установки игры или по другим причинам. Ведь программы и игры могут перезаписывать файлы библиотеки (см. последнее преимущество), вследствие чего тот или иной софт порой отказывает в работе.

Решение

Чтобы подобные ситуации не всплывали, в последних поколениях Виндовс появилась технология Side-by-side assembly. Она позволяет использоваться параллельно разные версии библиотек. Правда, это нововведение идёт в разрез с принципом модульности, который изначально был преимуществом.

В случаях, когда система выдаёт ошибку DLL, можно попробовать скачать и установить обновлённые отдельные компоненты или весь пакет целиком. Кстати, отследить, какие приложение используют те или иные файлы библиотек, можно при помощи специальных утилит, например, Dependency Walker .

Если вам станет что-то непонятно в компьютере или просто скучно, возвращайтесь. У меня всегда найдутся полезные статьи;)

DLL – расширение файлов, которые являются своего рода справочными материалами при выполнении тех или иных программ. Название типа файлов расшифровывется как «библиотека динамической компоновки ». Эти динамические библиотеки могут быть одновременно использованы разными приложениями. В каком-то смысле они также похожи на исполняемые файлы , однако отличаются значением некоторых полей. Самым ярким примером являются файлы драйверов , которые описывают правила взаимодействия устройства и ОС.

Чем открыть DLL

Прежде, чем рассказать, как открывать эти файлы следует обратить внимание пользователя на то, что особого смысла в открытии такого типа библиотек нет. Они содержат в себе информацию необходимую программе для выполнения. Крайне редко в этом типе файлов хранятся важные переменные (а не способ их вызова) или данные. Хотя, справедливости ради, отметим, что есть ряд компаний, которые всё-таки сумели расположить информацию, необходимую для работы программ в dll.

Правда, динамические библиотеки иногда подвергаются декомпилированию для получения хранящихся в них правил и принципов работы. Для этого существует несколько специальных программ .

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

Есть ли у данной программы достоинства ? Огромное количество – спектр работ, которые можно на ней выполнить ограничен лишь фантазией владельца. А недостаток всего один, но существенный – годовая подписка составляет около 500$.

Способ установки в систему

Но если писать и редактировать библиотеки нам не приходится, как обычным пользователям, то вот знание об их установке может быть полезным. Дело в том, что далеко не все программы снабжаются полным набором необходимых библиотек и подразумевается, что вместе с ними устанавливаются и отдельные компоненты (весьма распространённая деталь при установке игр), которые были забыты пользователем. Тогда требуется устанавливать , а точнее регистрировать файлы dll.

Сперва нужно найти сам файл. Благо, при тщательном поиске это не так уж и сложно и необходимые библиотеки встречаются довольно часто, даже отдельно от пакета, что не мешает их работе. Стоит отметить, что в случае с играми это бывают d3dx.dll которые могут отсутствовать в системе – в этом случае лучше установить пакет DirectX, а не ставить 150 библиотек вручную.

Но если нужно регистрировать новый dll для запуска программы, то лучше поместить его в каталог с программой. В ОС Windows 7 и выше присутствует возможность открытия командной строки из каталога, в иных же случаях предстоит открыть командную строку и используя команду cd добраться в нужный каталог.

Для указанных же версий ОС достаточно открыть нужный каталог и зажав шифт клацнуть по пустому месту правой кнопкой мыши . В ответ перед нами всплывёт контекстное меню, следующего вида:

Нажимаем на «открыть окно команд ». Перед нами появится командная строка, где нам нужно прописать следующее:

Данная команда добавит библиотеку в перечень используемых системой, экономя время на иные способы установки. Чтобы отменить регистрацию, следует использовать такую команду:

regsvr32 — u dllname.dll

Важно отметить , что dllname.dll введено для примера и вместо всего, что написано слева от точки (то есть вместо dllname) следует вводить название вашего файла. На изображении показано добавление в ОС Windows 10 dll файла от directX8.

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

Вы здесь, потому у вас есть файл, который имеет расширение файла, заканчивающийся в.dll. Файлы с расширением.dll может быть запущен только некоторыми программами. Вполне возможно, что.dll являются файлами данных, а не документы или средства массовой информации, что означает, что они не предназначены для просмотра на всех.

что такое&nbsp.dll&nbspфайл?

Эти DLL-файлы также известны как файлы Dynamic Link Library, и содержимое файла, прикрепленной с .dll расширения является набор скомпилированных ресурсов, таких как директив, процедур и библиотек драйвера, которые требуются встроенные приложения Windows, и сторонними программами, которые были разработаны для Microsoft Windows. Эти DLL-файлы позволяют программы для Windows, чтобы общие ресурсы в скомпилированных библиотек с другими выполнения applications.During, некоторые из этих приложений могут быть связаны с этими DLL ресурсов. Большинство из этих DLL-файлов уже в комплекте с системами Microsoft Windows, хотя некоторые программы предусматривают свои собственные DLL ресурсов после установки. Некоторые из этих DLL-файлов облегчения связи между системой Windows, соответствующий встроенный или сторонних приложений и ресурсов драйвера, необходимые для внешних и внутренних устройств ввода / вывода.

как открыть.dll файл?

Запустите.dll файл или любой другой файл на своем компьютере, дважды щелкнув его. Если ваши ассоциации файлов настроены правильно, приложение, которое предназначается, чтобы открыть свой.dll файл будет открыть его. Возможно, вы, возможно, потребуется загрузить или приобрести правильное применение. Кроме того, возможно, что у вас есть правильное применение на вашем компьютере, но.dll Файлы еще не связанные с ним. В этом случае, при попытке открыть.dll файл, вы можете сказать, Окна, какое приложение является правильным для этого файла. С тех пор, открывая.dll файл откроется правильное применение.

приложения, которые открываются.dll файл

Microsoft Windows Operating System

слово предупреждения

Будьте осторожны, не переименовать расширение на&nbsp.dll&nbspфайлы или любые другие файлы. Это не будет изменить тип файла. Только специальная программа для конвертирования можете изменить файл из одного типа файла в другой.

что такое расширение файла?

Расширение файла является набор из трех или четырех символов в конце имени файла, в этом случае,&nbsp.dll.&nbspРасширения файлов сказать вам, какой тип файла он есть, и сказать Окна, какие программы можно открыть. Окна часто связывает программу по умолчанию для каждого расширения файла, так что, когда вы дважды щелкните файл, программа запускается автоматически. При том, что программа больше не на вашем компьютере, вы можете иногда получить сообщение об ошибке при попытке открыть соответствующий файл.


Файлы формата DLL открываются специальными программами. Существует 2 типа форматов DLL, каждый из которых открывается разными программами. Чтобы открыть нужный тип формата, изучите описания файлов и скачайте одну из предложенных программ.

Чем открыть файл в формате DLL

Найти и установить любую недостающую или поврежденную DLL библиотеку поможет программа HELPER.DLL .

В файлах формата DLL содержатся настройки ссылки на различные ресурсы, используемые программой, например, иконки. DLL предназначены исключительно для ОС Windows. На других операционных системах открыть такие файлы можно только с помощью эмуляторов (исключением являются кроссплатформенные приложения для Mac OS). Нужно помнить, что современные программы не поддерживают файлы для 16-ти битной архитектуры.

Меры предосторожности

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

Программы для открытия файлов DLL

Просмотр исходного кода

Одним из самых распространенных способов, чтобы просмотреть расширение Dll, является . Программа имеет встроенные функции декомпиляции некоторых файлов, поэтому можно заниматься отладкой dll, а главное, она полностью бесплатна. Разумеется, гарантировать корректное отображение кода для всех файлов невозможно.

В качестве альтернативы можно использовать декомпилятор dotPeek . Он также бесплатен, однако способен работать исключительно с программами, написанными на C#.

Настройка интерфейса программы

Для этой цели лучше всего подходит . С помощью данной программы можно легко сменить иконки, диалоги или установить собственную анимацию. К сожалению, программа является платной даже для некоммерческого использования. Следует обратить внимание, что могут возникнуть проблемы с файлами больших размеров (около 1 ГБ и более).

Самым простым способом является использование Visual Studio от Microsoft. Это довольно функциональный инструмент, в число возможностей которого входит отладка программы, но поможет он только в случае, если на файле нет защиты.

Если же нужно просто скачать DLL взамен битого файла (или отсутствует Dll), то здесь поможет DLL-helper — полностью бесплатная программа.

Динамические web-страницы

Существует и другой формат DLL — файлы, генерирующие код для сайтов. Такие библиотеки можно открыть в любой удобной среде разработки, например, Visual Studio . Протестировать их в действии поможет браузер. Лучше использовать последние версии популярных обозревателей, в противном случае файл может отображаться некорректно.

Веб-страница, автоматически создающаяся во время доступа пользователя. Может объединять серверные сценарии, такие как Perl или , создающие -код для веб-страниц.

Веб-страницы в файлах расширения DLL чаще всего хранятся на веб-серверах Microsoft IIS. Расширение DLL должно отображаться на соответствующем механизме создания сценариев сервера для корректной обработки страницы.

Файл компилированной библиотеки, содержащий набор процедур и/или драйверов, на которые ссылается и которые выполняются программой. Позволяет различным программам получать доступ к общедоступным системным функциям посредством стандартных библиотек. Может динамически связываться в программе во время ее работы.

Многие файлы DLL(читается ДЛЛ) предоставляются операционной системой Windows, другие входят в состав программ Windows. Они также предоставляют различные программные функции, такие как соединение с внешними устройствами и входным и выходным сигналом жесткого диска. На них также могут ссылаться кросс-платформенные приложения для Mac.

Примечание: удаление или изменение содержимого файла DLL может стать причиной ошибок в работе программы, которая ссылается на файл. Поэтому файлы DLL не стоит открывать или редактировать.

Что такое DLL файлы, и для чего они нужны? Аббревиатура DLL – обозначает «Динамически Подключаемую Библиотеку». Она установлена, во всех операционных системах Windows, и практически каждая программа или игра на компьютере пользуется данной библиотекой. В ней содержится информация о конфигурации системы, совместимости устройств, наборе команд для правильной работы и многое другое. Некоторые файлы для игр имеют в своих папках уже готовые библиотеки, остальные пользуются системными.

Зачем нужны DLL компоненты

Если вкратце: что такое DLL файлы? – это компоненты библиотеки, а нужна она для запуска программ, приложений и игр. Компьютер включился, и система работает исправно. Вы еще ничего не запускали и не открывали, а уже десятки DLL файлов используются. Простые часы, информация о конфигурации системы, порядок запуска программ, оформление и многое другое используют библиотеку. Для того чтобы в текстовом документе начали появляться символы, соответствующие вашему вводу, нужна библиотека. По умолчанию система не знает, что означает нажатая вами клавиша,─ в этом его помогают компоненты DLL. Аналогичная ситуация со всеми подключаемыми устройствами: принтером, мышью, клавиатурой, флеш-картой. Именно библиотека DLL файлов «рассказывает» им, как работать с параметрами вашей системы.

Работоспособность элементов

Важно обновлять периодически систему и библиотеку, неактуальные файлы приведут к отказу работы программы. К примеру, вы установили игры пятилетней и большей давности, они у вас работают нормально. Далее вы поставили новую часть игры, которой не более года. Она может у вас не запуститься. Система выдаст следующее оповещение: ошибка DLL, отсутствует файл. Оно означает, что файлы нерабочие или вовсе его нет на компьютер. Связано это с тем, что программы или игры, которые пользуются библиотекой, могут вносить изменения. К примеру, вы установили игру, но параметры разрядности системы и версию ОС указали неверно.

Текущие файлы будут перезаписаны, и программа работать перестанет. Раз отсутствует DLL, значит, его нужно скачать и поместить в систему вручную. Но в большинстве случаев, новые игры требуют новых файлов, которых вообще не было в старых сборках системы, и решение одно — установить или обновить весь пакет.

У нас на сайте, Вы сможете скачать как отдельный DLL, так и весь пакет, в котором будут все файлы обновленные. Найти отсутствующий файл вы можете либо через поиск, либо по первой букве в верхнем меню. Как установить DLL файл и зарегистрировать прочтите в другой статье, где мы описали этот процесс максимально подробно.

Создание библиотеки динамической компоновки Dll: Справочник по C#

Иногда при запуске какой-либо программы появляется сообщение, что не найден файл *.dll. Для операционных систем Microsoft Windows, большая часть функциональных возможностей операционной системы обеспечивается библиотеками динамической компоновки (DLL). Кроме того, некоторые возможности программ могут быть реализованы в библиотеках DLL. Например некоторые программы могут содержать много различных модулей и при работе использовать только часть из них. Таким образом операционная система и программы загружаются быстрее, работают быстрее и занимают меньше места на диске компьютера.
Что такое DLL?
DLL — это библиотека, содержащая код и данные, которые могут использоваться несколько программами одновременно. Например, в операционных системах Windows, библиотека Comdlg32.dll выполняет общие функции, связанные с диалоговыми окнами. Таким образом каждая программа может использовать функцию, которая содержится в этой библиотеке для реализации диалогового окна Открыть . Это позволяет повысить уровень повторного использования кода и эффективного использования памяти.
С помощью библиотек можно реализовать модульность для программы, в виде отдельных компонентов. Например бухгалтерскую программу можно продать по модулям. Каждый модуль может быть загружен в основной программе во время выполнения установки. Отдельные модули загружается только при запросе функций заложенных в них, поэтому загрузка программы выполняется быстрее.
Кроме того обновления легче применить для каждого модуля, не влияя на другие части программы. Например имеется программа по зарплате и надо изменить налоговые ставки за каждый год. Когда эти изменения изолированы в библиотеке, можно применить обновления без необходимости построения или установки программы целиком. Давайте рассмотрим пример создания библиотеки с самыми простыми математическими методами, такие как произведение, деление, сумма и разность.
Для начала, создадим новый проект, для этого запустите Microsoft Visual Studio и перейдите в меню Файл -> Создать -> Проект… или выполните сочетание клавиш Ctrl+Shift+N.

В открывшемся диалоговом окне выберете версию Framework, а в левой части «Установленные шаблоны» выберете «Visual C#», в центральной части вам будет представлен список шаблонов, выберете «Библиотека классов» и введите имя библиотеки, можно оставить по умолчанию.

У вас откроется вкладка с классом по умолчанию.

По умолчанию создается класс Class1, переименуем его в класс Calculator. Для этого перейдите в меню Вид – > Классы или выполните сочетание клавиш Ctrl + W, с последующем нажатием клавиши C.

В правой части программы у вас откроется вкладка «Окно классов».

Выберете по умолчанию созданный класс Class1, сделайте клик правой клавишей мыши по нему и выберете «Переименовать…».

В открывшемся окне введите новое имя класса Calculator и нажмите кнопку OK, обратите внимание, что данное окно позволяет переименовать класс во всем проекте.

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

Добавим в класс Calculator несколько методов и добавим к ним описание.

По умолчанию для всех проектов стоит режим построения Debug(режим отладки), переведем проект в режим построения конечной версии (Release). Для этого перейдите в обозреватель решений и сделав клик правой клавишей мыши по названию проекта, выберете в открывшемся контекстном меню пункт «Свойства».

В открывшемся окне «Страницы свойств Решение “ClassLibrary1”» выберете везде конфигурацию Release, как показано на скриншоте ниже.

Наверно все замечали, что при наборе кода, появляется подсказка к методам или функциям. Мы задали такую подсказку в тегах . Но если сейчас просто выполнить построение библиотеки, то при подключении к другим проектам никаких подсказок видно не будет. Что бы устранить данную проблему, нам необходимо сформировать XML файл документации к проекту. Для этого в обозревателе решений выполните клик правой клавишей мыши по названию библиотеки и в открывшемся контекстном меню выберете пункт «Свойства».

После этих действий у вас откроется новая вкладка со свойствами проекта ClassLibrary1. Выберете в вкладку «Построение» и найдите раздел «Вывод», там вам будет предложено ввести путь куда будет выполнено построение конечной версии библиотеки и пункт необходимый нам для построения xml файла документации, тут вам необходимо просто поставить галочку как показано на скриншоте ниже. Тут важно чтобы библиотека и файл документации находились в одном месте, поэтому проверьте чтобы их путь вывода совпадал.

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

После этого, выполним построение решения. Нажав на клавиатуре клавишу F6.

Илон Маск рекомендует:  Как изменить разрешение экрана

Как только программа закончит построение, можно перейти в директорию с проектом и посмотреть что получилось. На этом этапе закончилось создание библиотеки.

Для проверки работоспособности библиотеки создадим тестовый проект. Выполните Файл -> Создать -> Проект…

Выберете из предложенных шаблонов, шаблон «Приложение Windows Forms Visual C#». Задайте имя проекта и нажмите кнопку OK.

После создания проекта, в обозревателе решений сделайте клик правой клавишей мыши по разделу «Ссылки» и выберете в появившемся контекстном меню пункт «Добавить ссылку…».

Выберете вкладку «Обзор» и укажите вашу библиотеку.

Если вы все успешно выполнили, в разделе «Ссылки» у вас появится название вашей библиотеки.

Сделайте клик правой клавишей мыши по главной форме вашего проекта и в открывшемся контекстном меню выберете пункт «Свойства».

В боковой панели откроются «Свойства» формы. Найдите метод Load и сделайте двойной клик левой клавишей мыши по нему, у вас откроется новая вкладка с добавленным методом Form1_Load.

Добавим пространство имен с названием нашей библиотеки.

Пропишите вызов нескольких методов из библиотеки и вывод результата в диалоговом окне «MessageBox». Обратите внимание что при выборе методом из библиотеки у вас показывается подсказка которую мы прописывали. Если такого не происходит то, xml файл документации отсутствует в директории с библиотекой. Пример подсказок вы можете посмотреть на скриншоте ниже.

Запустите проект, нажав клавишу F5. И вы увидите результат выполнения методов прописанных в библиотеке, с параметрами которые вы передали при вызове.

Ссылка для скачивания примера библиотеки: Яндекс.Диск

Для чего нужны библиотеки dll. Работа с библиотеками динамической компоновки (DLL). Динамическая загрузка и выгрузка DLL

И IBM OS/2; динамическая библиотека, позволяющая многократное применение различными программными приложениями. K DLL относятся также элементы управления ActiveX и драйверы. В мире UNIX аналогичные функции выполняют т. н. shared objects («разделяемые объекты»).

Формат файлов DLL придерживается тех же соглашений, что и формат исполняемых файлов, сочетая код, таблицы и ресурсы.

Цели введения DLL

Первоначально предполагалось, что введение DLL позволит эффективно организовать память и дисковое пространство, используя только один экземпляр библиотечного модуля для различных приложений. Это было особенно важно для ранних версий Microsoft Windows с жёсткими ограничениями по памяти.

Далее, предполагалось улучшить эффективность разработок и использования системных средств за счёт модульности. Замена DLL-программ с одной версии на другую должна была позволить независимо наращивать систему, не затрагивая приложений. Кроме того, библиотеки DLL могли использоваться разнотипными приложениями — например, Microsoft Office, Microsoft Visual Studio и т. п.

В дальнейшем идея модульности выросла в концепцию COM.

Фактически, полных преимуществ от внедрения DLL получить не удалось по причине явления, называемого DLL hell («ад DLL»). DLL Hell возникает, когда несколько приложений требуют одновременно различные, не полностью совместимые, версии DLL-библиотек, что приводит к сбоям в этих приложениях. Когда система выросла до определённых размеров, количество DLL стало превышать многие тысячи, не все из них обладали полной надёжностью и совместимостью, и конфликты типа DLL Hell стали возникать очень часто, резко понижая общую надёжность системы. Поздние версии Microsoft Windows стали разрешать параллельное использование разных версий DLL, что свело на нет преимущества изначального принципа модульности. Использование разных версий Dll стало возможным благодаря файлу манифеста (manifest), который хранится в ресурсах приложения или в виде отдельного файла в одном с приложением каталоге.

Примеры использования DLL в разных языках

Экспорт в DLL

Delphi

C и C++

C и C++

Подгрузка и импорт из DLL во время работы

Delphi

C и C++

Уязвимости в механизмах DLL

Уязвимость заключается в том, что многие программы при вызове функции LoadLibrary() не проверяют корректность пути, по которому эта библиотека может быть загружена. Таким образом, они позволяют произвести подмену выполняемой библиотеки. Это связано с тем, что поиск загружаемой библиотеки осуществляется в первую очередь в директории, содержащей образ исполняемого файла, который породил процесс (подмененная библиотека выполняется с привилегиями пользователя, запустившего процесс).

Библиотеки динамических ссылок (DLL) похожи на EXE, но они не являются непосредственно исполняемыми. Они похожи на файлы.so в Linux/Unix. Другими словами, DLL — это реализация разделяемых библиотек MS.

DLL файлы похожи на EXE, что сам формат файла тот же. И EXE, и DLL основаны на формате Portable Executable (PE). DLL могут также содержать COM-компоненты и библиотеки.NET.

Что содержит DLL?

DLL содержит функции, классы, переменные, пользовательские интерфейсы и ресурсы (такие как значки, изображения, файлы. ), которые использует EXE или другая библиотека.

Практически во всех операционных системах существует 2 типа библиотек. Статические библиотеки и динамические библиотеки. В Windows расширения файлов следующие: Статические библиотеки (.lib) и динамические библиотеки (.dll). Основное отличие состоит в том, что статические библиотеки связаны с исполняемым файлом во время компиляции; тогда как динамически связанные библиотеки не связаны до времени выполнения.

Подробнее о статических и динамических библиотеках:

Обычно вы не видите статические библиотеки, хотя на вашем компьютере, потому что статическая библиотека встроена непосредственно внутри модуля (EXE или DLL). Динамическая библиотека представляет собой автономный файл.

DLL может быть изменена в любое время и загружается только во время выполнения, когда EXE явно загружает DLL. Статическая библиотека не может быть изменена после ее компиляции в EXE. DLL можно обновлять индивидуально без обновления самого EXE.

Программа загружает DLL при запуске через Win32 API LoadLibrary или когда это зависимость от другой DLL. Программа использует GetProcAddress для загрузки функции или LoadResource для загрузки ресурса.

DLL файлы — это двоичные файлы, которые могут содержать исполняемый код и ресурсы, такие как изображения и т.д. В отличие от приложений, они не могут выполняться напрямую, но приложение загружает их по мере необходимости (или сразу во время запуска).

Насколько они важны?

Большинство приложений загружают файлы DLL, которые они требуют при запуске. Если какой-либо из них не найден, система вообще не сможет запустить процесс.

DLL файлы могут потребовать другие DLL файлы

Точно так же, как для приложения требуется DLL файл, DLL файл может зависеть от других файлов DLL. Если один из этих DLL файлов в цепочке зависимостей не найден, приложение не загружается. Это легко отлаживается с помощью любых инструментов зависимостей зависимостей, таких как Dependency Walker .

Их так много в системных папках

Большая часть функциональных возможностей системы представлена ​​пользовательской программе в виде файлов DLL, поскольку они являются стандартной формой совместного использования кода/ресурсов. Каждая функциональность хранится отдельно в разных DLL файлах, поэтому загружаются только необходимые файлы DLL и, следовательно, уменьшаются ограничения памяти в системе.

Установленные приложения также используют файлы DLL

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

Однако иногда обновления системы часто прерывают другие программы, когда существует несоответствие версии между совместно используемыми файлами DLL и требуемой программой. Системные контрольные точки и кеш-память DLL и т.д. Были инициативами M $для решения этой проблемы. Платформа.NET может не столкнуться с этой проблемой вообще.

Как мы узнаем, что внутри DLL файла?

Вы должны использовать внешний инструмент, например DUMPBIN или Dependency Walker, который не только покажет, какие публично видимые функции (известные как экспорт) внутри DLL файлов, а также какие другие DLL файлы, которые он требует, и которые экспортируют из этих DLL файлов, этот файл DLL зависит от.

Как мы их создаем/используем?

Обратитесь к документации по программному обеспечению от вашего поставщика. Для С++ обратитесь к LoadLibrary в MSDN.

Предположим, вы создаете исполняемый файл, который использует некоторые функции, найденные в библиотеке.

Если используемая библиотека статическая , компоновщик скопирует объектный код для этих функций непосредственно из библиотеки и вставляет их в исполняемый файл.


Теперь, если этот исполняемый файл запущен, он имеет все, что ему нужно, поэтому исполняемый загрузчик просто загружает его в память и запускает его.

Если библиотека динамическая , компоновщик не будет вставлять объектный код, а скорее вставляет заглушку, которая в основном говорит, что эта функция находится в этой DLL в этом месте.

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

Чтобы увидеть это в действии, удалите или переименуйте DLL и посмотрите, как загрузчик сообщит о недостающей ошибке DLL при попытке запустить исполняемый файл.

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

Одно последнее замечание, если вы не подключаетесь к DLL, тогда никакие заглушки не будут вставлены компоновщиком, но Windows по-прежнему предоставляет API GetProcAddress , который позволяет загрузить выполнение DLL после того, как исполняемый файл запущен.

Файлы DLL содержат Таблица экспорта , которая представляет собой список символов, которые могут быть просмотрены вызывающей программой. Символы обычно являются функциями с конвенция вызова C (__ stcall). Таблица экспорта также содержит адрес функции.

С помощью этой информации вызывающая программа может затем вызывать функции внутри DLL, даже если у нее не было доступа к DLL во время компиляции.

DLL (библиотеки динамических ссылок) и SL (разделяемые библиотеки, эквивалентные в UNIX) — это просто библиотеки исполняемого кода, которые могут быть динамически связаны с исполняемым файлом во время загрузки.

Статические библиотеки вставляются в исполняемый файл во время компиляции и фиксируются с этой точки. Они увеличивают размер исполняемого файла и не могут быть разделены.

Динамические библиотеки имеют следующие преимущества:

1/Они загружаются во время выполнения, а не компилируются, поэтому их можно обновлять независимо от исполняемого файла (все эти причудливые окна и диалоговые окна, которые вы видите в Windows, поступают из DLL, поэтому внешний вид вашего приложения может измените, не переписывая его).

2/Поскольку они независимы, код можно разделить на несколько исполняемых файлов — это экономит память, поскольку, если вы используете 100 приложений с одной DLL, в памяти может быть только одна копия DLL.

Их основным недостатком является преимущество # 1 — изменение библиотеки DLL независимо от приложения может привести к тому, что ваше приложение перестанет работать или начнет вести себя причудливо. Версии DLL, как правило, не очень хорошо управляются под Windows, и это приводит к причудливому названию «DLL Hell».

DLL или dynamic-link library это файл с дополнительными ресурсами, которые могут использоваться программами и самой операционной системой. В DLL файлы помещают исполняемый код и другие данные нужные различным программам при их выполнении. Один и тот же DLL файл может использоваться несколькими программами одновременно.

Для того чтобы понять, что такое DLL библиотека рассмотрим пример. В операционной системе есть DLL файл под названием Comdlg32. В нем содержатся ресурсы необходимые для создания диалоговых окон. Различные программы используют DLL файл Comdlg32 для того чтобы создавать диалоговые окна. Таким образом, один и тот же DLL файл обеспечивает нужными ресурсами большое количество программ. Такой подход позволяет экономить место на диске и более эффективно использовать оперативную память.

Использование DLL файлов имеет и другие преимущества. Так с помощью DLL файлов разработчик может создать модульную программу. В исполняемом EXE файле можно разместить только самые необходимые для работы программы ресурсы, а остальное в DLL файлах. А потом во время работы программы подключать только нужные в данный момент DLL файлы. Поскольку не нужные ресурсы не будут загружаться, программа будет работать значительно быстрее. Кроме этого, если программа построена по такому принципу, ее очень просто обновлять. Достаточно внести в изменения только в один DLL файл, а остальные останутся не тронутыми.

В операционной системе Windows также используются файлы.ocx (ActiveX), .cpl (Панель управления), .drv (драйверы). Они имеют такую же структуру и выполняют те же задачи что и DLL библиотеки.

Возможные проблемы с DLL файлами

Самой распространенной проблемой с DLL файлами является их отсутствие. Часто для работы программе нужны DLL файлы, которые распространяются отдельно. Яркий пример DirectX. Наверное, вы часто сталкивались с проблемой, когда программу нельзя запустить из-за отсутствия DLL файла DirectX.

Как правило, эта проблема решается очень просто. Нужно найти в Интернете и скачать файл об отсутствии которого сообщает программа. После этого скопируйте его в папку с игрой, а также в папки Windows и Windows\system32. В большинстве случаев этого достаточно для решения проблемы.

Сегодня расскажу о решении проблемы, которая часто возникает у пользователей. Ошибка связанная с отсутствием, какого либо, файла библиотеки dll. Эта ошибка появляется на вашем компьютере в случае если отсутствует в системе необходимый файл «динамических библиотек». Эти файлы необходимы для работы запускаемой программы, чаще это игра, которые выдают вам эту ошибку.

Из википедии:

DLL — «библиотека динамической компоновки», «динамически подключаемая библиотека», в операционных системах Microsoft Windows и IBM OS/2 — динамическая библиотека, позволяющая многократное использование различными программными приложениями. Эти библиотеки обычно имеют расширение DLL. Так же, как EXE, DLL могут содержать секции кода, данных и ресурсов.

Файлы данных с тем же форматом как у DLL, но отличающиеся расширением, или содержащие только секцию ресурсов, могут быть названы ресурсными DLL. В качестве примера можно назвать библиотеки иконок, иногда имеющие расширение ICL, и файлы шрифтов, имеющих расширение FON и FOT.

Первоначально предполагалось, что введение DLL позволит эффективно организовать память и дисковое пространство, используя только один экземпляр библиотечного модуля для различных приложений. Это было особенно важно для ранних версий Microsoft Windows с жёсткими ограничениями по памяти.

Далее предполагалось улучшить эффективность разработок и использования системных средств за счёт модульности. Замена DLL-программ с одной версии на другую должна была позволить независимо наращивать систему, не затрагивая приложений. Кроме того, динамические библиотеки могли использоваться разнотипными приложениями — например, Microsoft Office, Microsoft Visual Studio и т. п.

Как правило отсутствие этого файла на вашем компьютере вызвано двумя причинами:

  1. Необходимая библиотека не устанавливалась.
  2. Необходимый файл был удален программой чистки вашего компьютера, от мусора или не нужных программ. Эти программы не всегда удаляют только мусор и не нужные файлы.

Человеческий фактор я не рассматриваю (действия совершенные по не знанию и т. п.)

Где взять эти библиотеки, файлы?

Как правило операционная система содержит в себе необходимые библиотеки, последние версии, этих файлов. Но многими программы используют не только обновленные версии но и старые. Бывает наоборот программе нужны только новые библиотеки, а система давно не обновлялась.

Вы подумали, что надо просто обновить систему? Нет решение этой проблемы совсем в другом.

Устраняем ошибки.

Отсутствующие файлы могут содержаться в двух библиотеках.

Как правило если это игра то вам необходимо обновить или до установить пакет средств разработки DirectX.

Если это программа, то обычно недостает файлов Microsoft Visual C++ (MSVC) — интегрированная среда разработки.

Но бывает необходимо установить или обновить оба компонента.

Обновив оба компонента вы решите не только существующую проблему но и предотвратите возвращение к этому вопросу в последующем.

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

С обновлением Microsoft Visual C++ все сложнее. Microsoft Visual C++ содержит несколько редакций, и в какой редакции находится недостающий у вас файл не известно.

Можно скачать необходимую редакцию на сайте Microsoft. Но это более трудоемкий процесс, надо скачивать несколько версий библиотек.

DLL – расширение файлов, которые являются своего рода справочными материалами при выполнении тех или иных программ. Название типа файлов расшифровывется как «библиотека динамической компоновки ». Эти динамические библиотеки могут быть одновременно использованы разными приложениями. В каком-то смысле они также похожи на исполняемые файлы , однако отличаются значением некоторых полей. Самым ярким примером являются файлы драйверов , которые описывают правила взаимодействия устройства и ОС.

Чем открыть DLL

Прежде, чем рассказать, как открывать эти файлы следует обратить внимание пользователя на то, что особого смысла в открытии такого типа библиотек нет. Они содержат в себе информацию необходимую программе для выполнения. Крайне редко в этом типе файлов хранятся важные переменные (а не способ их вызова) или данные. Хотя, справедливости ради, отметим, что есть ряд компаний, которые всё-таки сумели расположить информацию, необходимую для работы программ в dll.

Правда, динамические библиотеки иногда подвергаются декомпилированию для получения хранящихся в них правил и принципов работы. Для этого существует несколько специальных программ .

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

Есть ли у данной программы достоинства ? Огромное количество – спектр работ, которые можно на ней выполнить ограничен лишь фантазией владельца. А недостаток всего один, но существенный – годовая подписка составляет около 500$.

Способ установки в систему

Но если писать и редактировать библиотеки нам не приходится, как обычным пользователям, то вот знание об их установке может быть полезным. Дело в том, что далеко не все программы снабжаются полным набором необходимых библиотек и подразумевается, что вместе с ними устанавливаются и отдельные компоненты (весьма распространённая деталь при установке игр), которые были забыты пользователем. Тогда требуется устанавливать , а точнее регистрировать файлы dll.

Сперва нужно найти сам файл. Благо, при тщательном поиске это не так уж и сложно и необходимые библиотеки встречаются довольно часто, даже отдельно от пакета, что не мешает их работе. Стоит отметить, что в случае с играми это бывают d3dx.dll которые могут отсутствовать в системе – в этом случае лучше установить пакет DirectX, а не ставить 150 библиотек вручную.

Но если нужно регистрировать новый dll для запуска программы, то лучше поместить его в каталог с программой. В ОС Windows 7 и выше присутствует возможность открытия командной строки из каталога, в иных же случаях предстоит открыть командную строку и используя команду cd добраться в нужный каталог.

Для указанных же версий ОС достаточно открыть нужный каталог и зажав шифт клацнуть по пустому месту правой кнопкой мыши . В ответ перед нами всплывёт контекстное меню, следующего вида:

Нажимаем на «открыть окно команд ». Перед нами появится командная строка, где нам нужно прописать следующее:

Данная команда добавит библиотеку в перечень используемых системой, экономя время на иные способы установки. Чтобы отменить регистрацию, следует использовать такую команду:

regsvr32 — u dllname.dll

Важно отметить , что dllname.dll введено для примера и вместо всего, что написано слева от точки (то есть вместо dllname) следует вводить название вашего файла. На изображении показано добавление в ОС Windows 10 dll файла от directX8.

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

Работа с библиотеками динамической компоновки (dll)

DLL (англ. Dynamic Link Library — «библиотека динамической компоновки», «динамически подключаемая библиотека») в операционных системах Microsoft Windows и IBM OS/2 — динамическая библиотека, позволяющая многократное использование различными программными приложениями. K DLL относятся также элементы управления ActiveX и драйверы. В мире UNIX аналогичные функции выполняют так называемые общие объекты.

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

Библиотеки динамической компоновки также имеют способность обеспечивать обмен данными между процессами. Когда в рамках DLL объявляется переменная, ее можно сделать разделяемой (shared). Все процессы, обращающиеся к библиотеке, для таких переменных будут использовать одно и то же место в физической памяти. (Здесь также важно не забыть о синхронизации.)

Протокол динамического обмена данными (Dynamic Data Exchange, DDE)

Этот протокол выполняет все основные функции для обмена данными между приложениями. Он очень широко использовался до тех пор, пока для этих целей не стали применять OLE (впоследствии ActiveX). На данный момент DDE используется достаточно редко, в основном для обратной совместимости.

Больше всего этот протокол подходит для задач, не требующих продолжительного взаимодействия с пользователем. Пользователю в некоторых случаях нужно только установить соединение между программами, а обмен данными происходит без его участия. Замечу, что все это в равной степени относится и к технологии OLE/ActiveX.

OLE (англ. Object Linking and Embedding)— технология связывания и внедрения объектов в другие документы и объекты, разработанная корпорацией Майкрософт.

В 1996 году Microsoft переименовала технологию в ActiveX.

OLE позволяет передавать часть работы от одной программы редактирования к другой и возвращать результаты назад. Например, установленная на персональном компьютере издательская система может послать некий текст на обработку в текстовый редактор, либо некоторое изображение в редактор изображений с помощью OLE-технологии.

Основное преимущество использования OLE (кроме уменьшения размера файла) в том, что она позволяет создать главный файл, картотеку функций, к которой обращается программа. Этот файл может оперировать данными из исходной программы, которые после обработки возвращаются в исходный документ.

OLE используется при обработке составных документов , может быть использована при передаче данных между различными несвязанными между собой системами посредством интерфейса переноса , а также при выполнении операций с буфером обмена. Идея внедрения широко используется при работе с мультимедийным содержанием на веб-страницах, где используется передача изображения, звука, видео, анимации в страницах HTML либо в других файлах, также использующих текстовую разметку (например, XML и SGML). Однако, технология OLE использует архитектуру «толстого клиента», то есть сетевой ПК с избыточными вычислительными ресурсами. Это означает, что тип файла либо программа, которую пытаются внедрить, должна присутствовать на машине клиента. Например, если OLE оперирует таблицами Microsoft Excel, то программа Excel должна быть инсталлирована на машине пользователя.

В 1996 году Microsoft переименовала технологию OLE 2.0 в ActiveX. Были представлены элементы управления ActiveX, ActiveX документы и технология Active Scripting. Эта версия OLE в основном используется веб-дизайнерами для вставки в страницы мультимедийных данных.

Это действительно универсальная технология, и одно из многих ее применений — межпроцессный обмен данными. Хотя, стоит отметить, что OLE как раз для этой цели и создавалась (на смену DDE), и только потом была расширена. Специально для обмена данными существует интерфейс IDataObject. А для обмена данными по сети используется DCOM, которую под некоторым углом можно рассматривать как объединение ActiveX и RPC.

В среде операционной системы Microsoft Windows NT вам доступно такое удобное средство передачи данных между параллельно работающими процессами, как каналы типа Pipe. Это средство позволяет организовать передачу данных между локальными процессами, а также между процессами, запущенными на различных рабочих станциях в сети.

Каналы типа Pipe больше всего похожи на файлы, поэтому они достаточно просты в использовании.

Через канал можно передавать данные только между двумя процессами. Один из процессов создает канал, другой открывает его. После этого оба процесса могут передавать данные через канал в одну или обе стороны, используя для этого хорошо знакомые вам функции, предназначенные для работы с файлами, такие как ReadFile и WriteFile. Заметим, что приложения могут выполнять над каналами Pipe синхронные или асинхронные операции, аналогично тому, как это можно делать с файлами. В случае использования асинхронных операций необходимо отдельно побеспокоиться об организации синхронизации.

Каналы — это очень мощная технология обмена данными. Наверное, именно поэтому в полной мере они поддерживаются только в Windows NT/2000. В общем случае канал можно представить в виде трубы, соединяющей два процесса. Что попадает в трубу на одном конце, мгновенно появляется на другом. Чаще всего каналы используются для передачи непрерывного потока данных.

Именованные и анонимные каналы

Существуют две разновидности каналов Pipe — именованные (Named Pipes) и анонимные (Anonymous Pipes).

Как видно из названия, именованным каналам при создании присваивается имя, которое доступно для других процессов. Зная имя какой-либо рабочей станции в сети, процесс может получить доступ к каналу, созданному на этой рабочей станции.

Анонимные каналы обычно используются для организации передачи данных между родительскими и дочерними процессами, запущенными на одной рабочей станции или на “отдельно стоящем” компьютере.

Анонимные каналы используются достаточно редко, они просто передают поток вывода одного процесса на поток ввода другого. Именованные каналы передают произвольные данные и могут работать через сеть. (Именованные каналы поддерживаются только в WinNT/2000.)

Сокеты (англ. socket — разъём) — название программного интерфейса для обеспечения обмена данными между процессами. Процессы при таком обмене могут исполняться как на одной ЭВМ, так и на различных ЭВМ, связанных между собой сетью. Сокет — абстрактный объект, представляющий конечную точку соединения.

Следует различать клиентские и серверные сокеты. Клиентские сокеты грубо можно сравнить с оконечными аппаратами телефонной сети, а серверные — с коммутаторами. Клиентское приложение (например, браузер) использует только клиентские сокеты, а серверное (например, веб-сервер, которому браузер посылает запросы) — как клиентские, так и серверные сокеты.

Интерфейс сокетов впервые появился в BSD Unix. Программный интерфейс сокетов описан в стандарте POSIX.1 и в той или иной мере поддерживается всеми современными операционными системами.

приложение память межпроцессный сокет

Каждый процесс может создать слушающий сокет (серверный сокет) и привязать его к какому-нибудь порту операционной системы (в UNIX непривилегированные процессы не могут использовать порты меньше 1024). Слушающий процесс обычно находится в цикле ожидания, то есть просыпается при появлении нового соединения. При этом сохраняется возможность проверить наличие соединений на данный момент, установить тайм-аут для операции и т.д.

Каждый сокет имеет свой адрес. ОС семейства UNIX могут поддерживать много типов адресов, но обязательными являются INET-адрес и UNIX-адрес. Если привязать сокет к UNIX-адресу, то будет создан специальный файл по заданному пути, через который смогут сообщаться любые локальные процессы путём чтения/записи из него (см. Доменный сокет Unix). Сокеты типа INET доступны из сети и требуют выделения номера порта.

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

Это очень важная технология, т.к. именно она отвечает за обмен данными в Интернет. Сокеты также часто используются в крупных ЛВС. Взаимодействие происходит через т.н. разъемы-«сокеты», которые представляют собой абстракцию конечных точек коммуникационной линии, соединяющей два приложения. С этими объектами программа и должна работать, например, ждать соединения, посылать данные и т.д. В Windows входит достаточно мощный API для работы с сокетами.

Почтовые слоты (mailslots)

Почтовые слоты — это механизм однонаправленного IPC. Если приложению известно имя слота, оно может помещать туда сообщения, а приложение-хозяин этого слота (приемник) может их оттуда извлекать и соответствующим образом обрабатывать. Основное преимущество этого способа — возможность передавать сообщения по локальной сети сразу нескольким компьютерам за одну операцию. Для этого приложения-приемники создают почтовые слоты с одним и тем же именем. Когда в дальнейшем какое-либо приложение помещает сообщение в этот слот, приложения-приемники получают его одновременно.

Как ни странно, объекты синхронизации тоже можно отнести к механизмам IPC. Конечно, объем передаваемых данных в данном случае очень невелик. Но именно эти объекты следует использовать, если одному процессу нужно передать другому что-то вроде «я закончил работу» или «я начинаю работать с общей памятью».

Microsoft Message Queue (MSMQ)

Расшифровывается это как Message Queuing (MSMQ) или Сервер очередей сообщений Microsoft. Очередь сообщений создана для взаимодействия приложений в распределенной среде (на разных компьютерах). Мы уже рассматривали подобные механизмы, например, socket или DCOM. Особенность MSMQ в том, что компьютеры не обязательно должны быть одновременно в сети. То есть можно отправить сообщение, можно получить, а за всем этим следит сервер MSMQ.

Есть несколько деталей, которые отличают очереди сообщений от других механизмов обмена данными в распределенной системе.


Доставка между клиентами одновременно не подключенными

Очередь сообщений поддерживается операционной системой

Очередь сообщений поддерживает транзакции

MSMQ 1.0 используется в Windows NT 4.0, Windows 95, and Windows 98.

MSMQ 2.0 используется в Microsoft® Windows® 2000.

Этот протокол действительно оправдывает свое название — он обеспечивает посылку сообщений между приложениями с помощью очереди сообщений. Основное его отличие от стандартной очереди сообщений Windows в том, что он может работать с удаленными процессами и даже с процессами, которые на данный момент недоступны (например, не запущены). Доставка сообщения по адресу гарантируется. Оно ставится в специальную очередь сообщений и находится там до тех пор, пока не появляется возможность его доставить.

Удаленный вызов процедур (Remote Procedure Call, RPC)

Строго говоря, это не совсем технология IPC, а скорее способ значительно расширить возможности других механизмов IPC. С помощью этой технологии общение через сеть становится совешенно прозрачным как для сервера, так и для клиента. Им обоим начинает казаться, что их «собеседник» расположен локально по отношению к ним .

Удалённый вызов процедур (или Вызов удалённых процедур) (от англ. Remote Procedure Call (RPC)) — класс технологий, позволяющих компьютерным программам вызывать функции или процедуры в другом адресном пространстве (как правило, на удалённых компьютерах). Обычно, реализация RPC технологии включает в себя два компонента: сетевой протокол для обмена в режиме клиент-сервер и язык сериализации объектов (или структур, для необъектных RPC). Различные реализации RPC имеют очень отличающуюся друг от друга архитектуру и разнятся в своих возможностях: одни реализуют архитектуру SOA, другие CORBA или DCOM. На транспортном уровне RPC используют в основном протоколы TCP и UDP, однако, некоторые построены на основе HTTP (что нарушает архитектуру ISO/OSI, так как HTTP изначально не транспортный протокол).

Идея вызова удалённых процедур (Remote Procedure Call — RPC) состоит в расширении хорошо известного и понятного механизма передачи управления и данных внутри программы, выполняющейся на одной машине, на передачу управления и данных через сеть. Средства удалённого вызова процедур предназначены для облегчения организации распределённых вычислений и создания распределенных клиент-серверных информационных систем. Наибольшая эффективность использования RPC достигается в тех приложениях, в которых существует интерактивная связь между удалёнными компонентами с небольшим временем ответов и относительно малым количеством передаваемых данных. Такие приложения называются RPC-ориентированными.

Характерными чертами вызова удалённых процедур являются:

· Асимметричность, то есть одна из взаимодействующих сторон является инициатором;

· Синхронность, то есть выполнение вызывающей процедуры приостанавливается с момента выдачи запроса и возобновляется только после возврата из вызываемой процедуры.

Реализация удалённых вызовов существенно сложнее реализации вызовов локальных процедур. Можно обозначить следующие проблемы и задачи, которые необходимо решить при реализации RPC:

· Так как вызывающая и вызываемая процедуры выполняются на разных машинах, то они имеют разные адресные пространства, и это создает проблемы при передаче параметров и результатов, особенно если машины находятся под управлением различных операционных систем или имеют различную архитектуру (например, используется прямой или обратный порядок байтов). Так как RPC не может рассчитывать на разделяемую память, то это означает, что параметры RPC не должны содержать указателей на ячейки нестековой памяти и что значения параметров должны копироваться с одного компьютера на другой. Для копирования параметров процедуры и результата выполнения через сеть выполняется их сериализация.

· В отличие от локального вызова удалённый вызов процедур обязательно использует транспортный уровень сетевой архитектуры (например TCP), однако это остается скрытым от разработчика.

· Выполнение вызывающей программы и вызываемой локальной процедуры в одной машине реализуется в рамках единого процесса. Но в реализации RPC участвуют как минимум два процесса — по одному в каждой машине. В случае, если один из них аварийно завершится, могут возникнуть следующие ситуации: при аварии вызывающей процедуры удалённо вызванные процедуры станут «осиротевшими», а при аварийном завершении удалённых процедур станут «обездоленными родителями» вызывающие процедуры, которые будут безрезультатно ожидать ответа от удалённых процедур.

· Существует ряд проблем, связанных с неоднородностью языков программирования и операционных сред: структуры данных и структуры вызова процедур, поддерживаемые в каком-либо одном языке программирования, не поддерживаются точно так же во всех других языках. Таким образом имеется проблема совместимости, до сих пор не решённая ни с помощью введения одного общепринятого стандарта, ни с помощью реализации нескольких конкурирующих стандартов на всех архитектурах и во всех языках.

Работа с DLL в Visual Basic (статья)

В данной статье описаны основные способы работы с DLL в языке программирования Visual Basic. Рассчитана прежде всего на начинающих программистов. Она поможет заинтересованному читателю ответить на ряд вопросов: что такое DLL, зачем его используют, как его правильно использовать и создавать.

Итак, что же такое DLL? Этой английской аббревиатурой словосочетания Dynamic-Link Library, что переводится как «динамически подключая библиотека», называют в операционных системах семейства Microsoft Windows динамические библиотеки, содержащие процедуры и функции, которые могут многократно использоваться различными программными приложениями.

Ранние версии Windows работали в условиях жёсткого ограничения памяти, а потому использование DLL должно было позволить более активно использовать её, ведь один экземпляр DLL, загруженный в память, может использоваться сразу несколькими программами. Однако существенных преимуществ полностью получить не удалось. Причиной является такое явление, как DLL Hell («DLL ад») — несколько программ работают с одинаковой библиотекой, однако с разными не полностью совместимыми версиями. Это приводило к большому количеству ошибок. Сейчас в Windows используется технология SxS, разрешающая параллельное использование разные версий библиотеки, что иногда сводит на нет её главное преимущество.

Тем не менее, DLL (к этому понятию также относят библиотеки ActiveX и драйверы) активно используются при разработке ПО.

Но в каких же случаях лучше использовать модули, а в каких DLL? Во-первых, модули, подключаемые к проекту, должны быть написаны на том языке, с которым работает среда разработки. DLL могут быть написаны на другом языке, хранятся они в уже откомпилированном виде. Во-вторых, использование DLL позволяет экономить память в том случае, если ею пользуются две или более программ одновременно (точнее, при использовании одной и той же версии). В-третьих, если функции не будут использоваться другими программами, то нет смысла создавать DLL. Тоже самое можно сказать про те случаи, когда нужно просто разбить для удобства большой код по модулям — удобнее работать с ними в одном проекте.

Говоря о DLL как о библиотеках подпрограмм, следует рассказать о соглашения вызова — это часть интерфейса приложения, которая регламентирует технические особенности вызова подпрограммы, передачи параметров, возврата из неё, передача результата в основную программу. Говоря простым языком — разные стандарты использования подпрограмм (функций и процедур).

Например, это расположения параметров подпрограммы: они могут быть в стеке или в регистрах. Различие существенное, от того-то эти соглашения не совместимы и нужно знать, какие используются в той или иной библиотеке.

Существует немало разных соглашений, но из них обратим внимание на stdcall и cdecl. Первый используют библиотеки WinAPI функций. Второй же пригодиться нам для использования функций, написанных на языке Си (cdecl — C Declaration). В обоих соглашениях аргументы передаются через стек, справа налево. Но в stdcall очистку стека производит вызываемая подпрограмма, а в cdecl — вызывающая программа.

Если что-то не поняли — не спешите ломать голову этими соглашениями, ведь для полного понимания работы с ними вам нужно знание основ Ассемблера. Не знаете? Вернетесь ещё к ним потом.
Внимание мы уделим stdcall и cdecl. Большинство библиотек у вас будут работать и с этим.

Каким же образом использовать DLL? Как воспользоваться функциями из них? Для этого их нужно подключить к программе. Различают два способа подключения: статический и динамический.

Статический. При использовании DLL загружается в память сразу при запуске программы, а выгружаются лишь при завершении работы программы. Преимущества: возможность вызова любой функции из библиотеки в любое время. Недостатки: нерациональное использование памяти в том случае, если какие-либо функции и процедуры из неё используются лишь 1 раз за всё время работы. Ведь она будет всё время в памяти, хотя логичнее её от туда выгрузить за ненадобностью.

Динамический. Загрузить и выгрузить DLL можно в любое время при работе программы. Преимущества: экономное использование памяти в тех случаях, когда функция используется один раз за всё время работы программы, после чего они уже не нужны. Недостатки: большее, по сравнению со статическим подключением, количество кода.

При данном способе подключения нужные функции объявляют в разделе деклараций:

Здесь:
Declare — ключевое слово, обозначающее, что дальше следует объявление функции из библиотеки
название_функции — название функции из библиотеки, которое будет использоваться у вас в программе. Может отличаться от названия функции в самой библиотеке (см. Alias)
Lib «имя_библиотеки» — название подключаемой библиотеки. Она должна находиться в папке System32, либо вместе с исполняемым файлом
Alias «название_функции_в_библиотеке» — необязательный параметр. Используется в том случае, если имя объявляемой функции в программе отличается от имени функции в библиотеке.

Visual Basic

В библиотеке функция сложения двух чисел называется Summ, а у нас Symma.
Используются подключенные таким образом функции точно так же, как и обычные. Например:

Visual Basic

Ну, это всё описываются библиотеки с stdcall. А как же cdecl? Ну, в VB есть ключевое слово cDecl, причём использоваться оно должно так:

Visual Basic

Однако вероятно вы получите Bad DLL Calling Convention (Error 49). Точнее, ваша программа будет работать лишь в Native (машинном) коде, т.е. уже полностью откомпилированная. А в режиме отладки (P-код), как и в самой IDE — нет. Дальнейшая разработка программы будет очень осложнена.
Мда, вот они какие — недокументированные возможности! Может есть шанс подключать cdecl библиотеки с динамическим подключением?

Как уже было сказано выше, при данном способе подключения библиотек кода будет намного больше.
Ну во-первых сразу скажу, что в Visual Basic нет возможности стандартными средствами подключать библиотеки динамическим способом.

Для этого нам нужно 3 WinAPI функции: LoadLibrary, GetProcAddress, FreeLibrary. Объявим их в разделе деклараций, а также 3 переменные, куда будем сохранять результаты:

Visual Basic

Как видите, используем мы эти функции из стандартной библиотеки kernel32.dll! Так что это статическое подключение, а значит как минимум эта библиотека у нас будет всегда в памяти.

Разберем подробнее эти функции, новые для нас. Как они работают, что делают и для чего нужны?

Эта функция отображает заданный исполняемый модуль в адресное пространство вызывающего процесса, или, проще говоря, загружает библиотеку в память.

Единственный её параметр lpLibFileName (строковой тип) содержит путь либо имя подключаемой библиотеки.

Если функция завершается успешно, то она возвращает дескриптор модуля (библиотеки). Если происходит ошибка — 0.

Эта функция извлекает адрес нужной процедуры или функции из DLL.

Имеет два параметра: hModule («хэндл», обычно целочисленный тип) и lpProcName (строковой тип). Первый параметр — дескриптор модуля. Получить его нам позволяет вышеописанная функция LoadLibrary. Второй параметр — имя нужной функции.

Если функция завершается успешно, то она возвращает адрес экспортируемой функции из модуля (библиотеки). Если происходит ошибка — 0.

Эта функция уменьшает итоговое число ссылок на DLL (если она используется одновременно несколькими приложениями), а если число ссылок становится равно 0, то выгружает библиотеку из памяти.

Имеет один параметр: hModule, т.е. дескриптор библиотеки (который, напомню, возвращает функция LoadLibrary).

Если функция завершается успешно, возвращаемой значение не равно нулю. Если происходит ошибка, то оно равно нулю.

Но основе этих функций составим программу, которая будет подключать динамически DLL (stdcall):

Visual Basic

Как вы сами видите, длина кода намного больше, чем при статической загрузке, поскольку мы включили сюда ещё и обработку ошибок при помощи конструкции if. Налицо — гибкость!

А теперь рассмотрим возможность динамического (впрочем, как я писал выше, работать со статическим очень сложно) подключения cdecl. Для этого, кроме упомянутых выше, нам понадобятся ещё функции CallWindowProc и CopyMemory. Сразу замечу, что необходимо знание Ассемблера для полного понимания работы такой программы.

Эта функция передает информацию сообщения процедуре заданного окна.

Имеет 5 параметров: lpFunc, который указывает на процедуру, и Param1-Param4, через которые передаются параметры функции. Все параметры имеют тип Long.

Возвращаемое значение определяет результат обработки и зависит от параметров.

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

Имеет 3 параметра: Dest — указатель в тот блок памяти, куда нужно произвести копирование, Src — указатель на тот блок памяти, который копируется, Length — количество байтов, которое должно передаваться.

Возвращаемое значение отсутствует.

В качестве примера использования мы будем вызывать функцию qsort из библиотеки ntdll.dll, написанной на Си (cdecl). Данная функция используется для быстрой сортировки массива.

Visual Basic

Подробное описание работы — в комментариях к коду.

Альтернативный код — с CallBack функцией. В отличие от предыдущего варианта, он гибче, т.к. позволяет менять критерий сравнения, а во-вторых здесь используется CopyMemory. Вместо функции RtlMoveMemory здесь используем API-функции GetMem4, PutMem4, GetMem2.

Visual Basic

По каким-то причинам в Microsoft решили, что возможность создавать обычные DLL в Visual Basic будет лишней, а потому создавать их так просто мы не сможем, во всяком случае, без бубна. Да, я говорю про обычные DLL, потому что можно создавать лишь ActiveX DLL. В чём же разница обычных DLL от ActiveX?

ActiveX была внедрена в Windows компанией Microsoft в 1996 году как продолжение развития её технологий OLE (Object Linking and Embedding) и COM (Component Object Model).

OLE — технология связи и внедрения объектов в другие документы и объекты. Она позволяет передавать данные от одной программы для редактирования другой. Так, например, изображение или рисунок в программе Microsoft Word можно редактировать в Paint, и при сохранении он автоматически измениться и в документе Word.

COM — технология создания программного обеспечения на основе взаимосвязанных компонентов. Воплощение идей объектно-ориентированного программирования (ООП): инкапсуляции и полиморфизма.

И вот мы имеем фреймворк ActiveX, совмещающий эти две технологии. Он активно используется при разработке форм приложений. Все кнопки, списки, диалоговые окна, «этикетки» (Label), поля ввода (Textbox), их которых мы собираем форму — всё это ActiveX. Вообще многие продукты Microsoft используют управляющий элементы ActiveX, что позволяет использовать их функционал в других приложениях. Подробнее об этом смотрите в моей статье об использовании компонента Windows Media Player для создания музыкального проигрывателя.

Итак, приступим к созданию ActiveX DLL! Запускаем Visual Basic, в окне New Project выбираем ActiveX DLL (либо в меню File-New Project). И вот уже перед нами и редактор кода! Процесс написания кода здесь ничем не отличается от написания обычной программы. Пишете код, сохраняете проект, компилируете библиотеку.
Но не забывайте тот факт, что ActiveX DLL, в отличие от обычной DLL, не библиотека процедур и функций, а библиотека классов! Так что здесь забудьте про процедурное программирование — только ООП! Пишем классы: поля, свойства, методы, инкапсуляция, наследование (кстати, в Visual Basic нет обычного наследования, так что это делать нужно через наследование интерфейсов), полиморфизм. В принципе это и есть главное отличие. Хотя написать процедуру как метод не составит проблем.

Коротко об использовании ActiveX DLL. Подключаются они точно так же, как и обычные, но с той разницей, что необходимо создать объект и вызывать его методы — это называют связыванием. Различают ранее и позднее связывание.

Ранее связывание осуществляется командой

Visual Basic

где myObj — имя объекта, а myClass — название класса в DLL. При таком связывании вся информация о методах, свойствах и событиях класса известна во время компиляции, потому вызов методов происходит также быстро, как и обычных функций в
программе.
При позднем связывании нужно сначала создать объект:

Visual Basic

после чего можно вызывать его метод:

Visual Basic

Проверка методов/свойств происходит во время выполнения программы, так что мы проигрываем раннему связыванию во времени, но зато этот способ более гибкий.

Если вас заинтересовала технология ActiveX и её возможности, рекомендую вам ознакомится со статьей Б.Л. Файфеля «COM в действии»: «Создаем ActiveX DLL»: и «Вопросы» (часто задаваемые вопросы про ActiveX).

Вообще-то создавать обычные DLL в Visual Basic, как уже было сказано выше, нельзя без «танцев с бубном». Но энтузиастами был создан Add-In для среды разработки Visual Basic, который позволяет создавать почти полноценные DLL на Visual Basic. Единственный, и самый существенный минус — невозможность использования созданных таким образом библиотек в других языках программирования. Загрузить Add-In можно по этой ссылке К архиву прилагается файл ReadMe с подробным описанием установки дополнения и его использования, а также пара примеров создания DLL.

Каким же образом мы компилируем библиотеки, если такой возможности в VB нет? Весь секрет в недокументированных возможностях link.exe («линкеры», как известно, выполняют компиляцию в всё с этим связанное). Если запустить его в DOS командой link.exe > c:/link.txt, то мы увидим множество различных ключиков. Их них наибольший интерес представляют /DLL и /DRIVER. Понятно, что компилятор Visual Basic 6 способен ещё и компилировать библиотеки с драйверами! Ну вот именно на первом ключе и основан принцип работы этой надстройки: перехватываем командную строку линкера, изменяем, вызываем настоящий линкер.
Только одно но. это скорее не продуманная реализация линкера, а баг. Он нарушает компоновку библиотеки, из-за чего она будет работать не стабильно. А именно — лишь в Visual Basic!

Если вас заинтересовало это, то подробнее ознакомиться с работой надстройки вы можете здесь.

Операционная система Microsoft Windows 3.1 для программиста

3. Библиотеки динамической компоновки

В этой главе мы расскажем вам о важнейшем механизме, лежащем в основе операционной системы Windows — механизме библиотек динамической компоновки DLL. Если вы уже заметили, в Windows имеется много важнейших механизмов и систем, например, только что рассмотренная система управления памятью, интерфейс графических устройств GDI, система динамического обмена данными DDE, система управления шрифтами, интерфейсы для мультимедиа, система динамической вставки и привязки объектов OLE, и так далее, и так почти до бесконечности.

Однако будем терпеливыми, и постараемся сосредоточиться, так как вся операционная система Windows и все ее драйверы (кроме виртуальных), а также другие расширения в некотором смысле есть ни что иное, как набор библиотек динамической компоновки. Редкое крупное приложение Windows обходится без собственных библиотек динамической компоновки, и ни одно приложение не может обойтись без вызова функций, расположенных в таких библиотеках. В частности, все функции программного интерфейса Windows находятся именно в библиотеках динамической компоновки DLL (Dynamic-Link Libraries ).

Что же это за библиотеки и почему они имеют такое большое значение?

3.1. Статическая и динамическая компоновка

Вспомним старые добрые времена, когда операционная система MS-DOS и компьютеры с памятью 1 Мбайт удовлетворяли запросы подавляющего большинства пользователей. Как создавался загрузочный файл программы для MS-DOS? Вы готовили исходный текст приложения на своем любимом языке программирования (Си, Паскаль, Модула-2 и т. д.), затем транслировали его для получения объектного модуля. После этого в дело включался редактор связей, который компоновал объектные модули, полученные в результате трансляции исходных текстов и модули из библиотек объектных модулей, в один exe-файл. В процессе запуска файл программы загружался полностью в оперативную память и ему передавалось управление.

Таким образом, редактор связей записывал в файл программы все модули, необходимые для работы. Для обращения к внешним по отношению к программам модулям операционной системы MS-DOS и модулям BIOS использовался механизм программных прерываний. В любой момент времени в оперативной и постоянной памяти компьютера находился весь код, необходимый для работы как запущенной программы, так и самой операционной системы MS-DOS.

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

В среде мультизадачной операционной системы, такой как Windows, OS/2 или UNIX, статическая компоновка неэффективна, так как приводит к неэкономному использованию очень дефицитного ресурса — оперативной памяти. Представьте себе, что в системе одновременно работают 5 приложений, и все они вызывают такие функции, как sprintf, memcpy, strcmp и т. д. Если приложения были собраны с использованием статической компоновки, в памяти будут находится одновременно 5 копий функции sprintf, 5 копий функции memcpy, и т. д (рис. 3.1). А ведь программы могут использовать и более сложные функции, например, предназначенные для работы с диалоговыми панелями или масштабируемыми шрифтами!

Рис. 3.1. Вызов функций при использовании статической компоновки

Очевидно, использование оперативной памяти было бы намного эффективнее, если бы в памяти находилось только по одной копии функций, а все работающие параллельно программы могли бы их вызывать.


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

При использовании динамической компоновки загрузочный код нескольких (или нескольких десятков) функций объединяется в отдельные файлы, загружаемые в оперативную память в единственном экземпляре. Программы, работающие параллельно, вызывают функции, загруженные в память из файлов библиотек динамической компоновки, а не из файлов программ.

Таким образом, используя механизм динамической компоновки, в загрузочном файле программы можно расположить только те функции, которые являются специфическими для данной программы. Те же функции, которые нужны всем (или многим) программам, работающим параллельно, можно вынести в отдельные файлы — библиотеки динамической компоновки, и хранить в памяти в единственном экземпляре (рис. 3.2). Эти файлы можно загружать в память только при необходимости, например, когда какая-нибудь программа захочет вызвать функцию, код которой расположен в библиотеке.

Рис. 3.2. Вызов функции при использовании динамической компоновки

В операционной системе Windows версии 3.1 файлы библиотек динамической компоновки (DLL-библиотеки) имеют расширение имени dll, хотя можно использовать любое другое, например, exe. В первых версиях Windows DLL-библиотеки располагались в файлах с расширением имени exe. Возможно поэтому файлы krnl286.exe, krnl386.exe, gdi.exe и user.exe имеют расширение имени exe, а не dll, не смотря на то, что перечисленные выше файлы, составляющие ядро операционной системы Windows, есть ни что иное, как DLL-библиотеки.

Механизм динамической компоновки используется не только в системе Windows. Более того, он был изобретен задолго до появления Windows. Например, в мультизадачных многопользовательских операционных системах VS1, VS2, MVS, VM, созданных для компьютеров IBM-370 и аналогичных (вспомните добрым словом ушедшую в прошлое серию ЕС ЭВМ и операционные системы SVS, TKS, СВМ, МВС), код функций, нужных параллельно работающим программам, располагается в отдельных библиотеках и может загружаться при необходимости в специально выделенную общую область памяти. Операционная система OS/2 также работает с DLL-библиотеками.

3.2. DLL-библиотеки в операционной системе Windows

Формат DLL-библиотеки почти идентичен формату загрузочного модуля приложения Windows, однако вы не можете «запустить» DLL-библиотеку на выполнение, как обычное приложение. И это понятно, так как назначение DLL-библиотек другое — они служат хранилищем функций, вызываемых приложениями во время работы. Функции, расположенные в DLL-библиотеках, могут вызывать функции, которые находятся в других библиотеках (рис. 3.3).

Рис. 3.3. Вызов функций из DLL-библиотек

Для того чтобы вам были понятны отличия между приложением и DLL-библиотекой, уточним такие понятия, как задача (task ), копия приложения (instance ) и модуль (module ).

Когда вы запускаете несколько копий одного приложения, Windows загружает в оперативную память только одну копию кода и ресурсов. Для каждой копии приложения создается отдельный сегмент данных, стек и очередь сообщений (рис. 3.4).

Рис. 3.4. Копии приложения и модуль приложения

Задачу (task) можно рассматривать как совокупность виртуального процессора и ресурсов, таких как стек, регистры процессора, глобальная память, очередь сообщений и т. д. В операционной системе Windows имеется база данных запущенных задач, в которой хранится вся относящаяся к задаче информация, например, идентификатор приложения, идентификатор модуля приложения и т. д.

Копия приложения (instance) является контекстом, в котором выполняется модуль приложения. Идентификатор копии приложения, который вы получаете через параметр hInstance функции WinMain, является идентификатором сегмента данных DGROUP, используемого при выполнении программного модуля.

Модуль приложения (module) состоит из исполнимого кода и ресурсов. Внутри Windows есть база данных модулей, в которой хранится такая информация, как ссылки на экспортируемые функции, расположение сегментов кода и сегментов, содержащих ресурсы. Так как модуль приложения не изменяется (сегменты кода и ресурсов не изменяются), все запущенные копии одного приложения могут им пользоваться.

DLL-библиотека также является модулем. Она находится в памяти в единственном экземпляре, содержит сегменты кода и ресурсы, а так же один сегмент данных (рис. 3.5). Можно сказать, что для DLL-библиотеки создается одна копия (instance), состоящая только из сегмента данных, и один модуль, состоящий из кода и ресурсов.

Рис. 3.5. Структура DLL-библиотеки в памяти

DLL-библиотека, в отличие от приложения, не имеет стека и очереди сообщения.

Функции, расположенные в модуле DLL-библиотеки, выполняются в контексте вызвавшей их задачи. При этом они пользуются стеком копии приложения, так как собственного стека в DLL-библиотеке не предусмотрено.

Тем не менее, функции, расположенные в DLL-библиотеке, пользуются сегментом данных, принадлежащей этой библиотеке, а не копии приложения. При этом возникают трудности, связанные с тем, что сегментный регистр SS, с помощью которого адресуется стек, указывает на стек копии приложения, а регистр DS — на сегмент данных DLL-библиотеки. В обычных приложениях Windows регистры SS и DS адресуют один и тот же автоматический сегмент данных. Позже мы займемся этим вопросом вплотную.

Для чего используются DLL-библиотеки ?

Прежде всего для экономии памяти, так как все запущенные приложения могут использовать один модуль DLL-библиотеки, не включая стандартные функции в состав своих модулей.

С помощью DLL-библиотек можно организовать коллективное использование ресурсов или данных, расположенных в сегменте данных библиотеки. Более того, вы можете создать DLL-библиотеки, состоящие только из одних ресурсов, например, из пиктограмм или изображений bitmap. В состав Windows входит DLL-библиотека moricons.dll, состоящая из одних пиктограмм. Файлы с расширением fon представляют собой ни что иное, как DLL-библиотеки, содержащие шрифты в виде ресурса.

Функции, входящие в состав DLL-библиотеки, могут заказывать блоки памяти с атрибутом GMEM_SHARE. Такой блок памяти не принадлежит ни одному приложению и поэтому не освобождается автоматически при завершении работы приложения. Так как в Windows версии 3.1 все приложения используют общую глобальную память, блоки памяти с атрибутом GMEM_SHARE можно использовать для обмена данными между приложениями. Управлять таким обменом могут, например, функции, расположенные в соответствующей DLL-библиотеке. Однако в следующих версиях Windows каждое приложение будет работать в собственном адресном пространстве, поэтому для организации обмена данных между приложениями следует использовать специальный механизм динамического обмена данными DDE, который мы рассмотрим позже в отдельной главе.

Использование DLL-библиотек повышает модульность приложений и самой операционной системы Windows. С точки зрения приложения DLL-библиотека является не более чем набором функций с тем или иным интерфейсом, а также, возможно, набором ресурсов. Внутреннее «устройство» и алгоритмы работы функций, а также используемые функциями структуры данных полностью скрыты от приложения. Поэтому при внесении изменений или усовершенствований в DLL-библиотеки нет необходимости выполнять повторную сборку приложений (если не изменился интерфейс или набор функций, входящих в библиотеку).

Область применения DLL-библиотек достаточно широка. Помимо предоставления приложениям функций организации пользовательского интерфейса и реализации различных расширений Windows типа мультимедиа или систем управления базами данных, DLL-библиотеки необходимы для обеспечения ряда системных операций.

Например, приложение может организовать «перехват» системных сообщений или функций, при этом соответствующие модули «перехватчика» необходимо располагать в фиксированном сегменте кода DLL-библиотеки. Для удаляемых (discardable) блоков памяти можно, вызвав функцию GlobalNotify, определить функцию, которой будет передаваться управление при попытке удалить блок из памяти. Такая функция должна находиться в фиксированном сегменте кода в DLL-библиотеке. Если ваше приложение обрабатывает аппаратные прерывания или само вызывает программные прерывания, ему также не обойтись без DLL-библиотек (единственный способ обработки прерываний в реальном времени — создание виртуального драйвера). Наконец, все обычные драйвера устройств в операционной системе Windows реализованы с помощью DLL-библиотек.

Даже если вы не собираетесь обрабатывать или вызывать прерывания и не разрабатываете собственный драйвер, отдельные подсистемы большого приложения имеет смысл оформлять в виде DLL-библиотек из соображений модульности и доступности библиотек для других приложений. Например, в приложении SMARTPAD мы создали орган управления Toolbar с использованием разработанного нами класса С++ Toolbar. Однако если бы мы сосредоточили все функции этого класса в DLL-библиотеке, нашим органом управления могли бы воспользоваться и другие созданные нами приложения.

Разумеется, у динамической компоновки есть и свои недостатки.

Во-первых, DLL-библиотеки сложнее в разработке по сравнению с обычными библиотеками статической компоновки. Приходится принимать во внимание неравенство содержимого регистров DS и SS во время выполнения функций, расположенных в DLL-библиотеке, а также то, что DLL-библиотека имеет единственный сегмент данных, общий для всех приложений, вызывающих функции из библиотеки.

Во-вторых, в дополнение к exe-файлу вместе с приложением необходимо устанавливать один или несколько dll-файлов, что в некоторой степени усложняет процесс установки и сопровождения приложения. Может также возникнуть ситуация, при которой приложение не находит свою DLL-библиотеку, несмотря на то, что нужная библиотека есть на диске.

В-третьих, без тщательного планирования состава функций, включаемых в DLL-библиотеку, экономии памяти может и не получиться. В частности, возможна такая ситуация, когда и приложение, и DLL-библиотека пользуются одними и теми же функциями стандартной библиотеки компилятора в варианте статической компоновки.

3.3. Структура DLL-библиотеки

DLL-библиотека состоит из нескольких специфических функций и произвольного набора функций, выполняющих ту работу, для которой разрабатывалась данная библиотека. Как мы уже говорили, DLL-библиотека может иметь (а может и не иметь) сегмент данных и ресурсы.

В заголовке загрузочного модуля DLL-библиотеки описаны экспортируемые точки входа, соответствующие всем или некоторым определенным в ней функциям. Приложения могут вызывать только те функции DLL-библиотеки, которые экспортируются ей.

Функция LibEntry

До тех пор, пока ни одно из приложений не затребовало функцию из DLL-библиотеки, сама библиотека находится в файле на диске. В оперативной памяти ее нет. Однако как только приложение затребует функцию из DLL-библиотеки или загрузит библиотеку в память явным образом, начнется процесс инициализации библиотеки. Этот процесс выполняется только один раз, так как в памяти может находиться только одна копия DLL-библиотеки.

В процессе инициализации после загрузки библиотеки в память Windows вызывает функцию LibEntry , которая должна быть определена в каждой DLL-библиотеке. Можно считать, что функция LibEntry является точкой входа библиотеки, получающей управление при загрузке библиотеки в память.

Задачей функции LibEntry является инициализация локальной области памяти, если она определена для DLL-библиотеки.

Функция LibEntry должна быть дальней функцией, составленной на языке ассемблера, так как она получает параметры через регистры процессора. Перечислим и опишем параметры, передаваемые функции LibEntry при загрузке DLL-библиотеки в память.

Visual Basic
Регистры Описание
DS Селектор, указывающий на сегмент данных DLL-библиотеки. Отметим, что хотя сразу после загрузки DLL-библиотека имеет собственный сегмент данных, в нем не определена область локальных данных. Для определения области локальных данных функция LibEntry должна вызвать функцию LocalInit
DI Идентификатор DLL-библиотеки, присвоенный ей операционной системой Windows после загрузки. По своему назначению аналогичен идентификатору приложения hInstance, передаваемому обычному приложению через соответствующий параметр функции WinMain. Идентификатор DLL-библиотеки используется функциями библиотеки при создании таких, например, объектов, как окна (если окно создается функцией, расположенной в DLL-библиотеке, при его создании следует использовать не идентификатор приложения hInstance, вызвавшего функцию, а идентификатор DLL-библиотеки)
CX Требуемый размер локальной области данных, указанный в операторе HEAPSIZE файла определения модуля DLL-библиотеки. При вызове функции инициализации локальной области памяти LocalInit в качестве значения параметра uStartAddr следует использовать нуль, а в качестве значения параметра uEndAddr — содержимое регистра CX
ES:SI Дальний указатель на строку параметров, которая может быть указана при явной загрузке DLL-библиотеки (позже мы рассмотрим различные способы загрузки DLL-библиотеки). Обычно этот параметр не используется

Вам не надо определять функцию LibEntry самостоятельно, так как при создании файла DLL-библиотеки редактор связей, входящий в систему разработки, включит уже имеющийся в стандартной библиотеке модуль. Этот стандартный модуль выполняет всю необходимую работу по инициализации локальной области памяти DLL-библиотеки (с помощью функции LocalInit) и затем вызывает функцию LibMain, которая будет описана в следующем разделе.

Иногда для DLL-библиотеки может потребоваться нестандартная инициализация. Только в этом случае вам придется разработать функцию LibEntry самостоятельно. За основу вы можете взять файл libentry.asm из SDK, который содержит исходный текст упомянутой выше функции.

Функция LibMain

Функция LibMain должна присутствовать в каждой стандартной DLL-библиотеке. Эту функцию вам надо определить самостоятельно, причем вы можете воспользоваться языком программирования С.

По своему назначению функция LibMain напоминает функцию WinMain обычного приложения Windows. Функция WinMain получает управление при запуске приложения, а функция LibMain — при загрузке DLL-библиотеки в память. Так же как и функция WinMain, функция LibMain имеет параметры, которые можно использовать для инициализации библиотеки.

Приведем прототип функции LibMain :

Параметр hInstance при вызове функции содержит идентификатор DLL-библиотеки. Это ни что иное, как содержимое регистра DI перед вызовом функции LibEntry.

Через параметр wDataSegment передается селектор, соответствующий сегменту данных DLL-библиотеки. Если DLL-библиотека не имеет сегмента данных, этот параметр содержит идентификатор DLL-библиотеки (точнее, идентификатор модуля DLL-библиотеки). Значение параметра wDataSegment соответствует содержимому регистра DS перед вызовом функции LibEntry.

Параметр wHeapSize содержит размер в байтах локальной области данных DLL-библиотеки. Если DLL-библиотека не имеет сегмента данных, в этом параметре находится нулевое значение.

И, наконец, через параметр lpszCmdLine передается указатель на командную строку, которую можно передать DLL-библиотеке при ее явной загрузке в память.

Если инициализация DLL-библиотеки выполнена успешно, функция LibMain должна возвратить ненулевое значение. Если в процессе инициализации произошла ошибка, следует возвратить нуль. В этом случае функция LibEntry также возвратит нуль. Это приведет к тому, что Windows выгрузит библиотеку из памяти.

Разрабатывая процедуру инициализации DLL-библиотеки, учтите, что функция LibMain вызывается только один раз, во время загрузки библиотеки в память. Не следует думать, что для каждого приложения, использующего одну и ту же DLL-библиотеку, будет вызвана функция LibMain. При попытке повторной загрузки уже загруженной ранее DLL-библиотеки будет увеличено содержимое счетчика использования библиотеки, но и только.

Если для каждого приложения в локальной области данных DLL-библиотеки необходимо выделять отдельные структуры данных, вам придется разработать собственную процедуру регистрации приложения.

Например, можно создать специальную функцию регистрации LibRegister, которая возвращает приложению указатель на выделенную для него в локальной области структуру данных. Вызывая функции из DLL-библиотеки, приложение передает им в качестве, например, первого параметра, этот указатель.

Перед завершением работы приложение должно вызвать созданную вами функцию, освобождающую выделенную структуру данных. Она может называться, например, LibUnregister.

Если функция LibMain заказывает блоки памяти из глобальной области данных, следует использовать флаг GMEM_SHARE. Такие блоки памяти будут принадлежать создавшей их DLL-библиотеке. Освобождение заказанных глобальных блоков памяти можно выполнить в функции WEP, получающей управление при выгрузке DLL-библиотеки из памяти.

Приведем пример простейшего варианта функции LibMain:

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

Функция WEP

DLL-библиотека в любой момент времени может быть выгружена из памяти. В этом случае Windows перед выгрузкой вызывает функцию WEP . Эта функция, как и функция LibMain, вызывается только один раз. Она может быть использована для уничтожения структур данных и освобождения блоков памяти, заказанных при инициализации DLL-библиотеки.

Приведем прототип функции WEP (при использовании системы разработки Borland Turbo C++ for Windows):

Параметр bSystemExit может принимать значения WEP_FREE_DLL и WEP_SYSTEM_EXIT . Этот параметр указывает причину выгрузки DLL-библиотеки из памяти. В первом случае выгрузка выполняется потому, что либо функциями библиотеки не пользуется ни одно приложение, либо одно из приложений выдало запрос на выгрузку. Если же параметр имеет значение WEP_SYSTEM_EXIT, выгрузка библиотеки происходит из-за завершения работы операционной системы Windows.

Функция WEP должна всегда возвращать значение 1.

Вам не обязательно самостоятельно определять функцию WEP. Так же как и функция LibEntry, функция WEP добавляется в DLL-библиотеку транслятором. Вы, однако, можете определить собственную функцию WEP, если перед выгрузкой DLL-библиотеки требуется освободить заказанные ранее блоки памяти.

Приведем пример простейшей функции WEP:

В операционной системе Windows версии 3.0 на использование функции WEP накладывались серьезные ограничения, которые делали ее практически бесполезной. Например, размер стека, используемого для работы этой функции, составлял всего 256 байт, чего совершенно недостаточно для вызова функций программного интерфейса Windows. Есть и другие проблемы, однако мы не будем их затрагивать из-за того, что версия 3.0 уже сильно устарела, а в версии 3.1 все эти ограничения сняты. Поэтому вы можете использовать функцию WEP для любых процедур, в частности, для освобождения памяти, полученной при инициализации в функции LibMain.

Экспортируемые функции

Кроме функций LibMain и WEP в DLL-библиотеке могут быть определены и другие функции (как мы уже говорили, существуют DLL-библиотеки, состоящие из одних ресурсов). Это могут быть экспортируемые и неэкспортируемые функции.

Экспортируемые функции доступны для вызова приложениям Windows. Неэкспортируемые являются локальными для DLL-библиотеки, они доступны только для функций библиотеки.

Самый простой способ сделать функцию экспортируемой в системе разработки Borland Turbo C++ for Windows — указать в ее определении ключевое слово _export. Мы использовали этот способ при определении функции окна. Для экспортируемой функции создается специальный пролог, необходимый для правильной загрузки сегментного регистра DS.

Есть и другой способ — можно перечислить все экспортируемые функции в файле определения модуля при помощи оператора EXPORTS :

В приведенном выше примере в разделе EXPORTS перечислены имена нескольких экспортируемых функций. Около некоторых имен после символа «@» указаны порядковые номера соответствующих функций в DLL-библиотеке.

Если вы не укажите порядковые номера экспортируемых функций, при компоновке загрузочного файла DLL-библиотеки редактор связи создаст свою собственную нумерацию, которая может изменяться при внесении изменений в исходные тексты функций и последующей повторной компоновке. Плохо это или хорошо?

Для ответа на этот вопрос следует знать, что ссылка на экспортируемую функцию может выполняться двумя различными способами — по имени функции и по ее порядковому номеру. Если функция вызывается по имени, ее порядковый номер не имеет значения. Однако вызов функции по порядковому номеру выполняется быстрее, поэтому использование порядковых номеров предпочтительнее.

Если при помощи файла определения модуля DLL-библиотеки вы задаете фиксированное распределение порядковых номеров экспортируемых функций, при внесении изменений в исходные тексты DLL-библиотеки это распределение не изменится. В этом случае все приложения, ссылающиеся на функции из этой библиотеки по их порядковым номерам, будут работать правильно. Если же вы не определили порядковые номера функций, у приложений могут возникнуть проблемы с правильной адресацией функции из-за возможного изменения этих номеров.

Чтобы сказанное стало более понятным, рассмотрим подробнее механизм, с помощью которого приложения ссылаются на функции из DLL-библиотек.

Импортирование функций

Когда вы используете статическую компоновку, то включаете в файл проекта приложения соответствующий lib-файл, содержащий нужную вам библиотеку объектных модулей. Такая библиотека содержит исполняемый код модулей, который на этапе статической компоновки включается в exe-файл загрузочного модуля.

Если используется динамическая компоновка, в загрузочный exe-файл приложения записывается не исполнимый код функций, а ссылка на соответствующую DLL-библиотеку и функцию внутри нее. Как мы уже говорили, эта ссылка может быть организована с использованием либо имени функции, либо ее порядкового номера в DLL-библиотеке.

Откуда при компоновке приложения редактор связей узнает имя DLL-библиотеки, имя или порядковый номер экспортируемой функции? Для динамической компоновки функции из DLL-библиотеки можно использовать различные способы.

Библиотека импорта

Для того чтобы редактор связей мог создать ссылку, в файл проекта приложения вы должны включить так называемую библиотеку импорта (import library ), созданную приложением Import Lib , входящим в состав системы разработки Borland Turbo C++ for Windows. Соответствующее средство имеется в SDK, а также в любой другой системе разработки приложений Windows.

Библиотека импорта создается либо на основе dll-файла библиотеки, либо на основе файла определения модуля, используемого для создания DLL-библиотеки.

В любом случае вам надо запустить приложение Import Lib, и из меню «File» выбрать строку «File Select. «. При этом на экране появится диалоговая панель «Select File», с помощью которой вы можете выбрать нужный вам dll- или def-файл (рис. 3.6).

Рис. 3.6. Работа с приложением Import Library

После выбора файла приложение Import Lib создаст библиотеку импорта в виде lib-файла, расположенного в том же каталоге, что и исходный dll- или def-файл. Этот файл необходимо включить в проект создаваемого вами приложения, пользующегося функциями DLL-библиотеки.

Следует заметить, что стандартные библиотеки систем разработки приложений Windows содержат как обычные объектные модули, предназначенные для статической компоновки, так и ссылки на различные стандартные DLL-библиотеки, экспортирующие функции программного интерфейса операционной системы Windows.

В состав системы разработки Borland C++ for Windows версии 4.0 и 4.01 входит DLL-библиотека, содержащая функции стандартной библиотеки компилятора. Эта библиотека расположена в файле с именем bc40rtl.dll. В проекте приложения вы можете определить, что для стандартных функций следует использовать динамическую компоновку. В этом случае размер полученного загрузочного модуля заметно сократится, однако для работы приложения будет нужен файл bc40rtl.dll.

Использование оператора IMPORTS

Использование библиотек импорта — удобный, но не единственный способ компоновки функций DLL-библиотеки. Этот способ можно рассматривать как способ неявной компоновки на этапе редактирования загрузочного модуля приложения, так как имена импортируемых функций нигде не перечисляются.

Другой способ основан на использовании в файле определения модуля приложения оператора IMPORTS . С помощью этого оператора можно перечислить импортируемые функции, указав имена функций или их порядковые номера , а также имена файлов соответствующих DLL-библиотек:

Во второй строке приведенного выше примера приложение импортирует функцию Msg из DLL-библиотеки dllsrc.dll, причем порядковый номер указанной функции в библиотеке равен 4.

В третьей строке из DLL-библиотеки dllsrc.dll импортируется функция с именем TellMe, причем ее порядковый номер не используется.

Для увеличения скорости работы приложения рекомендуется использовать способ, основанный на ссылке по имени DLL-библиотеки и порядковому номеру функции внутри этой библиотеки.

Динамический импорт функций во время выполнения приложения

В некоторых случаях невозможно выполнить динамическую компоновку на этапе редактирования. Вы можете, например, создать приложение, которое состоит из основного модуля и дополнительных, реализованных в виде DLL-библиотек. Состав этих дополнительных модулей и имена файлов, содержащих DLL-библиотеки, может изменяться, при этом в приложение могут добавляться новые возможности.

Если вы, например, разрабатываете систему распознавания речи, то можете сделать ее в виде основного приложения и набора DLL-библиотек, по одной библиотеке для каждого национального языка. В продажу система может поступить в комплекте с одной или двумя библиотеками, но в дальнейшем пользователь сможет купить дополнительные библиотеки и, просто переписав новые библиотеки на диск, получить возможность работы с другими языками. При этом основной модуль приложения не может «знать» заранее имена файлов дополнительных DLL-библиотек, поэтому динамическая компоновка с использованием библиотеки импорта или оператора IMPORTS файла определения модуля невозможна.


Однако приложение может в любой момент времени загрузить любую DLL-библиотеку, вызвав специально предназначенную для этого функцию программного интерфейса Windows с именем LoadLibrary . Приведем ее прототип:

Параметр функции является указателем на текстовую строку, закрытую двоичным нулем. В эту строку перед вызовом функции следует записать путь к файлу DLL-библиотеки или имя этого файла. Если путь к файлу не указан, при поиске выполняется последовательный просмотр следующих каталогов:

каталог, в котором находится операционная система Windows;

системный каталог Windows;

каталог, в котором находится загрузочный файл приложения, загружающего DLL-библиотеку;

каталоги, перечисленные в операторе описания среды PATH, расположенном в файле autoexec.bat;

каталоги, расположенные в сети, если для них определены пути поиска.

Если файл DLL-библиотеки найден, функция LoadLibrary возвращает идентификатор модуля библиотеки. В противном случае возвращается код ошибки, который по своему значению меньше величины HINSTANCE_ERROR, определенной в файле windows.h. Возможны следующие коды ошибок:

Код ошибки Описание
Мало памяти, неправильный формат загружаемого файла
2 Файл не найден
3 Путь к файлу не существует
5 Была предпринята попытка динамически загрузить приложение или произошла ошибка при совместном использовании файлов. Также возможно, что была предпринята попытка доступа к файлу в сети пользователем, не имеющим на это достаточных прав
6 Данная библиотека требует отдельный сегмент данных для каждой задачи
8 Мало памяти для запуска приложения
10 Неправильная версия операционной системы Windows
11 Неправильный формат загрузочного файла приложения Windows
12 Данное приложение разработано для операционной системы, отличной от Microsoft Windows
13 Данное приложение разработано для MS-DOS версии 4.0
14 Неизвестный тип исполняемого файла
15 Была предпринята попытка загрузить приложение, разработанное для реального режима работы процессора в среде ранних версий операционной системы Windows
16 Была предпринята попытка загрузить вторую копию исполняемого файла, содержащего сегменты данных, отмеченные как multiple, но не защищенные от записи
19 Попытка загрузки компрессованного выполнимого файла
20 Файл, содержащий DLL-библиотеку, имеет неправильный формат
21 Данное приложение работает только в среде 32-битового расширения Windows

Функция LoadLibrary может быть вызвана разными приложениями для одной и той же DLL-библиотеки несколько раз. В этом случае загрузка DLL-библиотеки выполняется только один раз. Последующие вызовы функции LoadLibrary приводят только к увеличению счетчика использования DLL-библиотеки.

В качестве примера приведем фрагмент исходного текста приложения, загружающего DLL-библиотеку из файла srcdll.dll:

Если DLL-библиотека больше не нужна, ее следует освободить с помощью функции FreeLibrary :

В качестве параметра этой функции следует передать идентификатор освобождаемой библиотеки.

Если счетчик использования DLL-библиотеки становится равным нулю (что происходит, когда все приложения, работавшие с библиотекой, освободили ее или завершили свою работу), DLL-библиотека выгружается из памяти. При этом вызывается функция WEP, выполняющая все необходимые завершающие действия.

Однако прежде чем выгружать библиотеку из памяти, приложение, вероятно, захочет вызвать из нее хотя бы одну функцию, поэтому теперь мы расскажем о том, как вызвать функцию из загруженной DLL-библиотеки.

Для того чтобы вызвать функцию из библиотеки, зная ее идентификатор, необходимо получить значение дальнего указателя на эту функцию, вызвав функцию GetProcAddress :

Через параметр hLibrary вы должны передать функции идентификатор DLL-библиотеки, полученный ранее от функции LoadLibrary.

Параметр lpszProcName является дальним указателем на строку, содержащую имя функции или ее порядковый номер, преобразованный макрокомандой MAKEINTRESOURCE.

Приведем фрагмент кода, в котором определяются адреса двух функций. В первом случае используется имя функции, а во втором — ее порядковый номер:

Перед тем как передать управление функции по полученному адресу, следует убедиться в том, что этот адрес не равен NULL:

Для того чтобы включить механизм проверки типов передаваемых параметров, вы можете определить свой тип — указатель на функцию, и затем использовать его для преобразования типа адреса, полученного от функции GetProcAddress:

А что произойдет, если приложение при помощи функции LoadLibrary попытается загрузить DLL-библиотеку, которой нет на диске?

В этом случае операционная система Windows выведет на экран диалоговую панель с сообщением о том, что она не может найти нужную DLL-библиотеку. В некоторых случаях появление такого сообщения нежелательно, так как либо вас не устраивает внешний вид этой диалоговой панели, либо по логике работы вашего приложения описанная ситуация является нормальной.

Для того чтобы отключить режим вывода диалоговой панели с сообщением о невозможности загрузки DLL-библиотеки, вы можете использовать функцию SetErrorMode , передав ей в качестве параметра значение SEM_NOOPENFILEERRORBOX .

Приведем прототип функции SetErrorMode:

Эта функция позволяет отключать встроенный в Windows обработчик прерывания MS-DOS INT 24h (критическая ошибка). В качестве параметра этой функции можно указывать комбинацию следующих значений:

Значение Описание
SEM_FAILCRITICALERRORS Операционная система Windows не выводит на экран сообщение обработчика критических ошибок, возвращая приложению соответствующий код ошибки
SEM_NOGPFAULTERRORBOX На экран не выводится сообщение об ошибке защиты памяти. Этот флаг может использоваться только при отладке приложений, если они имеют собственный обработчик такой ошибки
SEM_NOOPENFILEERRORBOX Если Windows не может открыть файл, на экран не выводится диалоговая панель с сообщением об ошибке

Функция SetErrorMode возвращает предыдущий режим обработки ошибки.

Файл определения модуля для DLL-библиотеки

Файл определения модуля для DLL-библиотеки отличается от соответствующего файла обычного приложения Windows. В качестве примера приведем образец такого файла:

В файле определения модуля DLL-библиотеки вместо оператора NAME должен находиться оператор LIBRARY , определяющий имя модуля DLL-библиотеки, под которым она будет известна Windows.

Остальные операторы те же, что и для обычного приложения, за исключением того что в файле определения модуля DLL-библиотеки не должно быть оператора STACKSIZE (так как у DLL-библиотеки нет стека).

Оператор CODE используется для определения атрибутов сегмента кода DLL-библиотеки.

Особенностью оператора DATA является использование параметра SINGLE. Так как DLL-библиотека находится в памяти в единственном экземпляре и может иметь только один сегмент данных, для описания сегмента данных библиотеки требуется параметр SINGLE.

Оператор HEAPSIZE определяет начальное значение локальной области памяти, которая будет выделена для DLL-библиотеки функцией LibEntry на этапе инициализации. Если DLL-библиотека не должна иметь локальную область данных, в качестве параметра следует указать нулевое значение:

И, наконец, оператор EXPORTS предназначен для перечисления имен и порядковых номеров функций, экспортируемых DLL-библиотекой.

Анализ DLL-библиотек при помощи утилиты tdump.exe

В комплекте системы разработки Borland Turbo C++ for Windows входит утилита tdump.exe , предназначенная для работы в среде MS-DOS. С помощью этой утилиты вы сможете проанализировать содержимое любой DLL-библиотеки, определив имена экспортируемых функций, их порядковые номера, имена DLL-библиотек и номера функций, импортируемых из этих библиотек и т. д.

В системном каталоге Windows имеется DLL-библиотека toolhelp.dll, предназначенная для создания отладочных средств и работы с внутренними структурами данных Windows. Мы выбрали эту библиотеку для наших исследований в основном из-за ее небольшого размера. Описание самой библиотеки выходит за рамки данного тома «Библиотеки системного программиста».

Итак, скопируйте библиотеку в любой временный каталог и введите в среде MS-DOS (или в среде виртуальной машины MS-DOS) следующую команду:

В результате в файл toolhelp.map будет записано подробное описание библиотеки toolhelp.dll. Мы приведем полученный листинг с нашими комментариями.

В начале файла DLL-библиотеки находится заголовок в формате MS-DOS. Он нас не интересует.

Далее в листинге приводится информация о заголовке загрузочного файла в формате Windows. Это так называемый заголовок нового исполняемого формата.

Обратите внимание, что в заголовке присутствует информация об адресе точки входа (Program entry Point). Начальное содержимое указателя стека (Initial Stack Pointer) равно нулю, так же как и начальный размер стека (Initial Stack Size). Это понятно, так как DLL-библиотека не имеет собственного стека.

В то же время начальный размер локальной области данных отличен от нуля и равен 512 байт (Initial Local Heap Size). Из заголовка можно также определить, что модуль DLL-библиотеки состоит из двух сегментов (Segment Count).

Далее в листинге приведены различные флаги. В частности, видно, что сегмент данных DGROUP имеет атрибуты single и может использоваться совместно различными приложениями (shared). Данный модуль может работать только в защищенном режиме (Protected mode only) и является ни чем иным, как DLL-библиотекой (Module type — Dynamic link Library(DLL)).

Затем в листинге перечисляются различные таблицы с указанием их смещения и размера:

Это таблица сегментов. В ней описаны два сегмента. Первый сегмент является сегментом кода, второй — сегментом данных.

Далее приводится информация о ресурсах DLL-библиотеки. Таблица ресурсов описывает единственный ресурс типа Version info, описывающий версию модуля.

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

Таблица ссылок на модули содержит имена модулей (DLL-библиотек), на которые ссылаются функции, расположенные в исследуемой библиотеке. Как видно из листинга, функции библиотеки toolhelp.dll ссылаются на модули KERNEL и USER. Эти модули являются основными компонентами операционной системы Windows и расположены, соответственно, в файлах krnl386.exe, krnl286.exe и user.exe.

Таблица входов (Entry Table) описывает экспортируемые функции. Для каждой функции приводится ее порядковый номер и смещение.

Имена и порядковые номера экспортируемых функций приведены в таблице нерезидентных имен (Non-Resident Name Table):

Далее в листинге описываются ссылки на импортируемые модули. Каждая такая ссылка состоит из имени модуля (в нашем случае это KERNEL или USER) и порядкового номера импортируемой функции. Сделав дамп файла krnl386.exe при помощи утилиты tdump.exe, вы сможете определить, что ссылке KERNEL.3 соответствует функция GetVersion, ссылке KERNEL.4 — функция LocalInit, а ссылке KERNEL.5 — функция LocalAlloc.

3.4. Приложение DLLCALL

Исходный текст простейшей DLL-библиотеки приведен в листинге 3.1. Как видно из листинга, в библиотеке определены всего три функции — LibMain, WEP и Msg.

Листинг 3.1. Файл dllcall/dllsrc.cpp

Функция LibMain проверяет размер локальной области данных, заказанной для DLL-приложения функцией LibEntry. Этот размер определяется значением, указанным в файле определения модуля DLL-библиотеки при помощи оператора HEAPSIZE и передается функции LibMain через параметр wHeapSize. Если DLL-библиотека имеет локальную область данных, на этапе инициализации ее необходимо расфиксировать для того чтобы разрешить Windows при необходимости произвольно изменять логический адрес сегмента данных в процессе перемещения сегментов. Использованный способ расфиксирования сегмента данных был описан в предыдущей главе и основан на использовании макрокоманды UnlockData.

После инициализации, которая в нашем простейшем примере всегда выполняется успешно, функция WinMain возвращает признак успешной инициализации — значение 1.

Задача функции WEP в нашем случае сводится к возврату значения 1, означающего успешное завершение.

Функция Msg — единственная функция предназначена для вывода строки сообщения, адрес которой передается ей в качестве параметра. Так как эта функция определена с ключевым словом _export, она может быть вызвана любым приложением. Именно эту функцию мы будем вызывать из приложения DLLCALL, исходные тексты которого приведены ниже.

Файл определения модуля для DLL-библиотеки имеет некоторые особенности (листинг 3.2).

Листинг 3.2. Файл dllcall/dll.def

Во-первых, в нем нет оператора NAME, предназначенного для идентификации приложения. Вместо него используется оператор LIBRARY. Этот оператор указывает, что данный файл описывает не приложение, а DLL-библиотеку.

Во-вторых, в операторе DATA указан параметр single, так как в памяти может находиться только одна копия DLL-библиотеки и, соответственно, может существовать только один сегмент данных.

И в-третьих, в файле определения модуля нет оператора STACKSIZE, так как DLL-библиотека не может иметь стек.

Для создания библиотеки вы можете воспользоваться файлом dllsrc.prj, который есть на дискете, продаваемой вместе с книгой в каталоге dllcall.

В файла проекта DLL-библиотеки, сделанной с помощью системы разработки Borland Turbo C++ for Windows, вам необходимо указать правильный тип приложения. Для этого в меню «Options» выберите строку «Application. » и в появившейся не экране диалоговой панели «Application Options» нажмите на кнопку «Windows DLL» (рис. 3.7). После этого нажмите на кнопку «OK».

Рис. 3.7. Диалоговая панель «Application Options»

Обратите внимание на то, что по умолчанию при создании DLL-библиотеки все функции, определенные в ней, становятся экспортируемыми (Windows DLL all functions exportable). Это означает, что все функции, определенные вами в DLL-библиотеке, имеют специальный пролог и эпилог, предназначенный для правильной загрузки регистра DS (в этот регистр записывается селектор сегмента данных DLL-библиотеки). Кроме того, все эти функции перечисляются в заголовке загрузочного dll-файла библиотеки.

По умолчанию для DLL-библиотеки используется компактная модель данных. В этой модели существует один сегмент кода и несколько сегментов данных. Кроме того, для ссылки на данные всегда используются дальние указатели, состоящие из селектора и смещения. Последнее обстоятельство очень важно. Вспомним, что при вызове функции из DLL-библиотеки регистр DS указывает на локальный сегмент данных библиотеки, а регистр SS — на сегмент данных вызывающего приложения. Так как трансляторы языка С передают параметры через стек, а также используют стек для размещения локальных переменных, вы не сможете адресовать параметры и локальные переменные через регистр DS (он указывает на сегмент данных DLL-библиотеки, а параметры и локальные переменные находятся в сегменте данных приложения). Очевидный выход — использование компактной или большой модели памяти, в которых используются дальние указатели на переменные.

Исходный текст приложения DLLCALL, вызывающего функцию Msg из нашей DLL-библиотеки, приведен в листинге 3.3.

Листинг 3.3. Файл dllcall/dllcall.cpp

Обратите внимание на то, что функция Msg описана как внешняя:

Файл определения модуля для приложения DLLCALL приведен в листинге 3.4. Он не имеет никаких особенностей.

Листинг 3.4. Файл dllcall/dllcall.def

Файл проекта приложения DLLCALL включает в себя библиотеку импорта dllsrc.lib, которую мы сделали из DLL-библиотеки dllsrc.dll при помощи приложения Import Lib, входящего в состав системы разработки Borland Turbo C++ for Windows.

3.5. Приложение DISCARD

В предыдущей главе мы приводили исходные тексты приложений GMEM и LMEM, которые, кроме всего прочего, демонстрировали приемы работы с удаляемой памятью. В этих приложениях мы заказывали удаляемые блоки памяти из, соответственно, глобальной и локальной области памяти, удаляли их а затем пытались зафиксировать, чтобы получить их линейный адрес. Так как блоки памяти были удалены, нам приходилось их восстанавливать.

Мы отметили, что приложение может создать собственную функцию извещения, которая будет получать управление при попытке Windows удалить глобальные блоки памяти, заказанные как удаляемые (если для них определен флаг GMEM_NOTIFY). Однако, как мы уже говорили, функция извещения должна располагаться в DLL-библиотеке, причем в фиксированном сегменте кода, так как она может быть вызвана из любого контекста, а не только из контекста вашего приложения.

Теперь, когда мы умеем создавать свои DLL-библиотеки, мы можем испытать работу механизма оповещения о попытке удаления глобального блока памяти .

Приложение DISCARD (листинг 3.5), сделанное на базе приложения GMEM, заказывает удаляемый блок памяти и назначает собственную процедуру извещения об удалении глобальных блоков памяти. Процедура размещена в DLL-библиотеке dll.dll, исходные тексты которой мы также приведем.

Листинг 3.5. Файл discard/discard.cpp

DLL-библиотека, в которой расположена функция извещения, составлена нами с использованием языка программирования C, а не C++. Это сделано для упрощения экспортирования функции, которая в данном случае экспортируется с использованием своего порядкового номера. Подробнее этот вопрос мы рассмотрим при описании исходного текста DLL-библиотеки, а пока заметим, что так как для функции извещения использован язык C, мы должны это отметить в прототипе функции, включаемой в исходный текст приложения, составленного на языке C++:

После запуска приложения функция WinMain определяет размер доступной памяти, вызывая функцию GlobalCompact, а затем выводит его на экран.

После этого функция WinMain устанавливает процедуру извещения, вызывая функцию GlobalNotify и передавая ей в качестве параметра адрес внешней по отношению к приложению функции извещения NotifyProc, расположенной в DLL-библиотеке:

Каждая копия приложения может вызывать функцию GlobalNotify только один раз.

Задача функции извещения заключается в том, чтобы предотвратить удаление блока памяти. Это сделать очень просто, достаточно того, чтобы функция извещения вернула нулевое значение.

После установки функции извещения приложение заказывает удаляемый блок памяти, указывая среди прочих флаг GMEM_NOTIFY :

Если этот флаг не будет указан, Windows при необходимости удалит блок без вызова процедуры извещения.

После получения блока памяти приложение пытается его удалить, вызывая функцию GlobalDiscard (можно было бы, конечно, подождать, пока этот блок будет удален самой операционной системой Windows, однако вы можете прождать до утра):

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

Если же процедура извещения разрешает удаление блока памяти, при попытке фиксирования блока мы получим состояние ошибки. В этом случае приложение восстанавливает и фиксирует блок памяти с выдачей соответствующего сообщения на экран.

Файл определения модуля приложения DISCARD приведен в листинге 3.6.

Листинг 3.6. Файл discard/discard.def

Исходный текст DLL-библиотеки приведен в листинге 3.7.

Листинг 3.7. Файл discard/dll.c

Эта библиотека исключительно проста, так как помимо стандартных функций LibMain и WEP в ней определена только одна функция извещения NotifyProc.


Изучение последней также не вызовет ни малейшего затруднения. Функция NotifyProc возвращает значение 0, запрещая Windows удалять блок памяти. Если надо разрешить удаление блока памяти, необходимо вернуть значение 1.

Обратим внимание на файл определения модуля DLL-библиотеки, приведенный в листинге 3.8.

Листинг 3.8. Файл discard/dll.def

Исходя из требований функции извещения, сегмент кода DLL-библиотеки сделан фиксированным. Кроме того, мы использовали оператор EXPORTS для экспортирования функции извещения и задали для этой функции порядковый номер.

Теперь о том, почему для создания DLL-библиотеки мы выбрали язык C, а не С++.

Как вы знаете, трансляторы языка C++ «разукрашивают» имена функций в объектном модуле, добавляя к ним символы, обозначающие типы аргументов и тип возвращаемого значения. Когда в файле определения модуля в разделе EXPORTS мы перечисляем имена функций, при сборке загрузочного файла DLL-библиотеки редактор связей будет искать в объектном модуле функции с перечисленными именами. Если же исходный текст составлен на языке C++, имена, расположенные в объектном модуле, будут мало напоминать использованные в исходном тексте. В результате редактор связей выведет сообщение о том, что он не может найти в объектном модуле указанные в файле определения модуля экспортируемые функции.

Если же исходный текст DLL-библиотеки составлен на языке C, эти проблемы исчезнут. Однако в этом случае при вызове таких экспортируемых функций из приложений, составленных на языке C++, вам придется объявить их как extern «C».

Если же для разработки DLL-библиотеки используется язык C++, для обеспечения доступа к экспортируемым функциям вы можете либо использовать библиотеку импорта, созданную приложением IMPLIB, либо описать экспортируемую функцию следующим образом (в качестве примера использован исходный текст одной из функций DLL-библиотеки, описанной в разделе «Приложение WINHOOK»):

Описание extern «C» отменяет для определяемой функции соглашение языка C++ об именах функций.

3.6. Фильтры

В операционной системе Windows, в основе которой лежит механизм обмена сообщениями, имеется очень мощное средство, позволяющее организовать фильтрацию или перехват любых сообщений. Причем можно фильтровать сообщения, предназначенные как для некоторых, так и для всех приложений. Вы можете создать свой фильтр, получающий управление до того, как то или иное сообщение достигнет очереди сообщений или перед вызовом соответствующей функции окна. Фильтр может оставить перехваченное сообщение без изменения, изменить его или даже изъять.

Можно встроить несколько однотипных фильтров. При этом организуется цепочка фильтров. Первым получит управление тот фильтр, который был встроен в последнюю очередь.

Для чего можно использовать фильтры?

С помощью фильтров вы можете перехватить сообщения, поступающие в любые диалоговые панели, полосы просмотра, меню и т. п., причем как для отдельного приложения, так и для всех приложений сразу. Можно «отобрать» сообщения у функций GetMessage, PeekMessage, SendMessage. Можно записывать и затем проигрывать события, связанные с перемещением мыши и использованием клавиатуры. Фильтры облегчают создание обучающих приложений, которые работают совместно с обычными приложениями Windows в режиме обучения. Обучающие приложения может контролировать действия пользователя, когда он работает с приложением.

В качестве примера в разделе «Приложение WINHOOK» мы расскажем вам о том, как можно с помощью фильтров переключать раскладку клавиатуры. Мы приведем исходные тексты несложного руссификатора клавиатуры, позволяющего использовать в операционной системе Windows символы кириллицы.

Установка фильтра

Для установки фильтра в операционной системе Windows версии 3.1 следует использовать функцию SetWindowsHookEx (в Windows версии 3.0 для этой цели была предназначена функция SetWindowsHook ):

Параметр idHook определяет тип встраиваемого фильтра. В качестве значения для этого параметра можно использовать одну из следующих констант:

Константа Назначение фильтра
WH_CALLWNDPROC Для функции окна. Используется в Windows версии 3.0 и 3.1. Можно устанавливать для отдельной задачи или для всей системы
WH_CBT Для обучающих программ. Можно устанавливать для отдельной задачи или для всей системы
WH_DEBUG Для отладкиИспользуется в Windows версии 3.1. Можно устанавливать для отдельной задачи или для всей системы
WH_GETMESSAGE Фильтр сообщений. Получает управление после выборки сообщения функцией GetMessageИспользуется в Windows версии 3.0 и 3.1. Можно устанавливать для отдельной задачи или для всей системы
WH_HARDWARE Фильтр для сообщений, поступающих от нестандартного аппаратного обеспечения, такого как система перьевого ввода. Используется в Windows версии 3.1. Можно устанавливать для отдельной задачи или для всей системы
WH_JOURNALPLAYBACK Фильтр для «проигрывания» событийИспользуется в Windows версии 3.0 и 3.1. Можно устанавливать только для всей системы
WH_JOURNALRECORD Фильтр для записи событийИспользуется в Windows версии 3.0 и 3.1. Можно устанавливать только для всей системы
WH_KEYBOARD Фильтр сообщений, поступающих от клавиатуры. Используется в Windows версии 3.1. Можно устанавливать для отдельной задачи или для всей системы
WH_MOUSE Фильтр сообщений, поступающих от мыши. Используется в Windows версии 3.1. Можно устанавливать для отдельной задачи или для всей системы
WH_MSGFILTER Фильтр сообщений, который получает управление после выборки, но перед обработкой сообщений, поступающих от диалоговых панелей или меню. Используется в Windows версии 3.0 и 3.1. Можно устанавливать для отдельной задачи или для всей системы
WH_SHELL Фильтр для получения различных извещений от операционной системы Windows. Используется в Windows версии 3.1. Можно устанавливать для отдельной задачи или для всей системы
WH_SYSMSGFILTER Фильтр вызывается операционной системой после того, как диалоговая панель или меню получат сообщение, но перед обработкой этого сообщения. Данный фильтр может обрабатывать сообщения для любых запущенных приложений Windows. Используется в Windows версии 3.0 и 3.1. Можно устанавливать только для всей системы

Параметр lpfn функции SetWindowsHookEx должен определять адрес функции встраиваемого фильтра (или, иными словами, функции перехвата сообщений).

Функция фильтра может находиться либо в приложении, устанавливающем фильтр, либо (что значительно лучше) в DLL-библиотеке. Если функция находится в приложении, или в DLL-библиотеке, загружаемой явным образом при помощи функции LoadLibrary, в качестве параметра lpfn следует использовать значение, полученное от функции MakeProcInstance. Если же для импортирования функций из DLL-библиотеки используется библиотека импорта (как в описанном ниже приложении WINHOOK), параметр lpfn может содержать непосредственный указатель на функцию фильтра.

Через параметр hInstance функции SetWindowsHookEx следует передать идентификатор модуля, в котором находится встраиваемая функция фильтра. Если функция фильтра определена внутри приложения, в качестве этого параметра необходимо использовать идентификатор текущей копии приложения, передаваемой через соответствующий параметр функции WinMain. Если же функция фильтра находится в DLL-библиотеке, данный параметр должен содержать идентификатор модуля библиотеки, передаваемый через параметр hInstance функции LibMain.

Последний параметр функции hTask должен содержать идентификатор задачи, для которой определяется функция фильтра. Если последний параметр указан как NULL, фильтр встраивается для всех задач, работающих в системе.

Если приложение встраивает фильтр для себя, оно должно определить идентификатор задачи, соответствующий собственной копии приложения. Это проще всего сделать, вызвав функцию GetCurrentTask :

Можно определить идентификатор задачи исходя из идентификатора окна, созданного этой задачей. Для этого следует воспользоваться функцией GetWindowTask :

Эта функция возвращает идентификатор задачи, создавшей окно с идентификатором hwnd.

Функция SetWindowsHookEx возвращает 32-разрядный идентификатор функции фильтра, который следует сохранить для дальнейшего использования, или NULL при ошибке.

В приведенном ниже фрагменте кода, взятом из приложения WINHOOK, устанавливается фильтр для сообщений, поступающих во все приложения от клавиатуры:

Исходный текст функции фильтра приведен (с сильными сокращениями) ниже:

После выполнения всех необходимых действий функция фильтра передает управление по цепочке другим фильтрам (что необязательно). Для этого вызывается функция CallNextHookEx :

Параметр hHook содержит идентификатор текущей функции фильтра.

Параметр code содержит код фильтра, который должен передаваться следующему фильтру в цепочке.

Параметры wParam и lParam содержат, соответственно, 16- и 32-битовый дополнительные параметры.

Параметры code, wParam и lParam функции CallNextHookEx полностью соответствуют параметрам функции фильтра, которая будет рассмотрена нами позже.

Отмена фильтра

Фильтр, установленный функцией SetWindowsHookEx, можно отменить или удалить при помощи функции UnhookWindowsHookEx :

В качестве единственного параметра этой функции следует передать идентификатор функции фильтра, полученный от функции SetWindowsHookEx.

Если отмена фильтра выполнена успешно, функция UnhookWindowsHookEx возвращает значение TRUE. В случае возникновения ошибки возвращается FALSE.

Функции фильтра

Функция фильтра должна иметь следующий прототип:

Имя функции фильтра может быть любым, так как при установке фильтра вы должны указать функции SetWindowsHookEx указатель на функцию фильтра.

Параметр code может определять действия, выполняемые функцией фильтра. В операционной системе Windows версии 3.0 этот параметр мог принимать отрицательные значения. В этом случае функция фильтра должна была передавать управление следующему в цепочке фильтру при помощи функции DefHookProc. Операционная система Windows версии 3.1 никогда не вызывает функцию фильтра с отрицательным значением параметра code.

Назначение параметров wParam и lParam зависит от типа фильтра, задаваемого при помощи параметра idHook функции SetWindowsHookEx. Мы не будем подробно описывать все возможные типы фильтров, так как это займет очень много времени. При необходимости вы сможете найти полное описание в документации, поставляющейся вместе с SDK. Рассмотрим в деталях только самые интересные, на наш взгляд, типы фильтров.

Фильтр WH_CALLWNDPROC

Приведем прототип функции фильтра типа WH_CALLWNDPROC (для функции можно использовать любое имя):

Функция CallWndProc обязательно должна находиться DLL-библиотеке. Она вызывается операционной системой Windows после вызова функции SendMessage, но перед тем, как сообщение попадет в функцию окна, для которой оно предназначено. Фильтр может изменить любые параметры сообщения или его код.

Если код действия (параметр code) меньше нуля, функция фильтра должна вызвать функцию CallNextHookEx, не изменяя перехваченное сообщение.

Если сообщение послано текущей задачей, значение параметра wParam отлично от нуля, в противном случае оно равно NULL.

Параметр lParam содержит указатель на структуру, которая описывает перехваченное сообщение (эта структура на описана в файле windows.h):

Функция фильтра должна всегда возвращать нулевое значение.

Заметим, что после установки фильтра WH_CALLWNDPROC производительность операционной системы Windows заметно уменьшится, поэтому использование такого фильтра оправдано только при отладке приложения или для создания приложений, специально предназначенных для отладки других приложений Windows.

Фильтр WH_CBT

Большинство приложений, созданных фирмой Microsoft для своей операционной системы Windows, имеют встроенные обучающие системы, предназначенные для того, чтобы пользователь мог быстрее освоить работу с приложением. Например, текстовый процессор Microsoft Word for Windows версий 2.0 и 6.0 имеет очень удобную и легкую в использовании обучающую систему. Эта обучающая система не только рассказывает пользователю о том, как надо работать с текстовым процессором, но и, что очень важно, дает ему возможность попробовать выполнить те или иные действия самостоятельно. Когда пользователь пытается работать самостоятельно, все выглядит так, как будто он имеет дело с настоящим текстовым процессором, но при этом его действия ограничиваются обучающей системой.

Для облегчения создания подобных обучающих программ приложения могут установить фильтр WH_CBT, специально предназначенный для организации контроля за действиями пользователя со стороны обучающих программ. Мы не беремся утверждать, что обучающая программа для текстового процессора Microsoft Word for Windows построена с использованием этого фильтра, однако, вполне вероятно, что это так и есть.

Приведем прототип функции фильтра WH_CBT:

Данная функция должна располагаться в DLL-библиотеке. Она вызывается операционной системой перед выполнением таких действий, как создание, активизация, удаление, перемещение и изменение размеров окна, перед удалением сообщений мыши или клавиатурных сообщений из системной очереди сообщений, перед передачей фокуса ввода и т. д.

Фильтр может разрешить или запретить выполнение перечисленных выше операций, возвращая соответствующее значение.

В зависимости от параметра code меняется назначение параметров wParam и lParam. Перечислим возможные значения для параметра code и кратко опишем назначение остальных параметров функции фильтра WH_CBT.

Значение параметра code Описание
HCBT_ACTIVATE Фильтр вызывается перед активизацией любого окна. Если функция возвращает FALSE, окно активизируется, если TRUE — нет. Параметр wParam содержит идентификатор активизирующегося окна. Параметр lParam содержит указатель на структуру CBTACTIVATESTRUCT :

Флаг fMouse содержит TRUE, если окно активизируется в результате щелчка мыши, поле hWndActive содержит идентификатор активного окна

HCBT_CREATEWND Фильтр вызывается перед созданием окна. Если функция фильтра возвращает FALSE, создание окна разрешается, если TRUE — нет. Параметр wParam содержит идентификатор создаваемого окна. Параметр lParam содержит дальний указатель LPCREATESTRUCT на структуру CREATESTRUCT :
HCBT_DESTROYWND Фильтр вызывается перед уничтожением окна. Если функция возвращает TRUE, уничтожение окна отменяется. Параметр wParam содержит идентификатор уничтожаемого окна. Параметр lParam содержит 0
HCBT_MINMAX Фильтр вызывается перед выполнением минимизации или максимизации окна. Если функция фильтра возвращает TRUE, перечисленные операции не выполняются. Параметр wParam содержит идентификатор окна, для которого выполняется минимизация или максимизация. Старшее слово параметра lParam равно нулю, младшее содержит одну из констант, описанных в файле windows.h с префиксом SW_, такие как SW_HIDE, SW_SHOWNORMAL, SW_SHOWMINIMIZED, SW_SHOWNOACTIVATE, SW_SHOW, SW_MINIMIZE, SW_SHOWMINNOACTIVE, SW_SHOWNA, SW_RESTORE
HCBT_MOVESIZE Фильтр вызывается перед перемещением или изменением размера окна. Если функция фильтра возвращает TRUE, выполнение операции отменяется. Параметр wParam содержит идентификатор окна, для которого выполняется перемещение или изменение размера. Параметр lParam содержит дальний указатель на структуру RECT, описывающую прямоугольную область
HCBT_SYSCOMMAND Фильтр вызывается при обработке системной команды. Вызов функции фильтра выполняется из функции DefWindowProc. Если функция фильтра возвращает TRUE, выполнение системной команды отменяется. Параметр wParam содержит код системной команды, такой, как SC_CLOSE, SC_HSCROLL, SC_MINIMIZE и т. д.Если параметр wParam содержит код команды SC_HOTKEY (активизация окна, связанного с клавишей ускоренного выбора, назначенной приложением), младшее слово параметра lParam содержит идентификатор окна, для которого назначена клавиша ускоренного выбора. Для остальных команд значение этого параметра не определено
HCBT_CLICKSKIPPED Фильтр вызывается при удалении сообщения мыши из системной очереди сообщений, при условии, что дополнительно определен фильтр WH_MOUSE. Параметр wParam содержит код сообщения мыши. Параметр lParam содержит дальний указатель на структуру MOUSEHOOKSTRUCT :
HCBT_KEYSKIPPED Фильтр вызывается при удалении клавиатурного сообщения из системной очереди сообщений, при условии, что дополнительно определен фильтр WH_KEYBOARD. Параметр wParam содержит виртуальный код клавиши.содержимое параметра lParam аналогично содержимому соответствующего параметра клавиатурных сообщений WM_KEYDOWN и WM_KEYUP
HCBT_SETFOCUS Фильтр вызывается при установке фокуса ввода. Если функция фильтра возвращает значение TRUE, фокус не устанавливается. Параметр wParam содержит идентификатор окна, получающего фокус ввода. Младшее слово парамера lParam содержит идентификатор окна, теряющего фокус ввода. Старшее слово парамера lParam всегда содержит NULL
HCBT_QS Фильтр вызывается при удалении из системной очереди сообщения WM_QUEUESYNC, предназначенного для использования обучающим приложением. Это сообщение позволяет ему определить момент завершения того или иного события в главном приложении. Тех, кого интересуют подробности, мы отсылаем к документации, поставляющейся вместе с SDK

Фильтр WH_DEBUG

Приведем прототип функции фильтра типа WH_DEBUG :

Фильтр WH_DEBUG предназначен для отладчиков и должен находиться в DLL-библиотеке. Он вызывается перед вызовом других фильтров, установленных функцией SetWindowsHookEx.

Параметр wParam содержит идентификатор задачи, которая установила фильтр.

Параметр lParam содержит дальний указатель на структуру DEBUGHOOKINFO :

В этой структуре в поле hModuleHook находится идентификатор модуля, содержащего функцию фильтра, поля lParam, wParam, code содержат параметры, передаваемые функции фильтра. Поле reserved не используется.

Функция фильтра типа WH_DEBUG может предотвратить вызов другого фильтра, для чего она должна возвратить значение TRUE. Если она вернет FALSE, управление будет передано соответствующему фильтру.

Фильтр WH_GETMESSAGE

Фильтр WH_GETMESSAGE получает управление, когда функция GetMessage или PeekMessage возвращают выбранное из очереди сообщение. Функция фильтра должна находиться в DLL-библиотеке.

Приведем прототип функции фильтра типа WH_GETMESSAGE:

Параметр lParam содержит указатель на структуру MSG , содержащую перехваченное сообщение:

Функция фильтра может изменить любой параметр сообщения и даже его код. В последнем случае произойдет замена одного сообщения на другое.

Возвращаемое функцией фильтра значение должно всегда равняться нулю.

Фильтр WH_HARDWARE

Фильтр WH_HARDWARE предназначен для перехвата сообщений, поступающих от нестандартных устройств ввода, таких, как устройства перьевого ввода (клавиатура и мышь — это стандартные устройства ввода). Функция фильтра должна находиться в DLL-библиотеке.

Приведем прототип функции фильтра типа WH_HARDWARE:

Структура HARDWAREHOOKSTRUCT описана в файле windows.h:

В этой структуре поле hWnd содержит идентификатор окна, которому предназначено сообщение, поле wMessage содержит код сообщения, поля wParam и lParam содержат дополнительную информацию, зависящую от кода сообщения.

Фильтр WH_JOURNALRECORD

Фильтр WH_JOURNALRECORD вызывается, когда Windows удаляет сообщения из системной очереди. Функция фильтра должна находиться в DLL-библиотеке.

Приведем прототип функции фильтра типа WH_JOURNALRECORD:

Данный фильтр предназначен для записи перехваченных сообщений в память или файл. Он не может изменять или удалять сообщения из системной очереди.

Параметр code может принимать одно из трех значений:

Значение параметра code Описание
HC_ACTION Windows извлекает сообщение из системной очереди
HC_SYSMODALON Windows выводит на экран системную модальную диалоговую панель. Начиная с этого момента приложение должно остановить запись сообщений
HC_SYSMODALOFF Windows удаляет системную модальную диалоговую панель, так что теперь можно продолжить запись сообщений

Структура EVENTMSG описана в файле windows.h:

Фильтр WH_JOURNALPLAYBACK

Фильтр WH_JOURNALPLAYBACK используется для «проигрывания» сообщений, записанных фильтром WH_JOURNALRECORD. Если установлен этот фильтр, обычный ввод при помощи мыши или клавиатуры отключается. Функция фильтра должна находиться в DLL-библиотеке.

Приведем прототип функции фильтра типа WH_JOURNALPLAYBACK:

Перед возвратом управления функция фильтра WH_JOURNALPLAYBACK должна записать по адресу, переданному ей через параметр lParam, структуру данных, записанную ранее функцией фильтра WH_JOURNALRECORD.

Функция фильтра должна вернуть интервал времени ожидания (в машинных тиках) перед тем как Windows начнет обработку сообщения. Если вернуть нулевое значение, ожидание выполняться не будет.

Фильтр WH_KEYBOARD

Фильтр WH_KEYBOARD получает управление, когда функции GetMessage или PeekMessage возвращают сообщения WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP или WM_CHAR. Функция фильтра должна находиться в DLL-библиотеке.

Приведем прототип функции фильтра типа WH_KEYBOARD:

Параметр code может принимать значения HC_ACTION и HC_NOREMOVE. В первом случае перехваченное сообщение после обработки будет удалено из системной очереди сообщений, во втором — останется в этой очереди (т. к. оно было выбрано при помощи функции PeekMessage с параметром PM_NOREMOVE). Если сообщение останется в очереди, таблица состояния клавиатуры, которую можно получить при помощи функции GetKeyboardState, может не отражать состояние клавиатуры на момент выборки сообщения.

Параметры wParam и lParam содержат ту же самую информацию, что и соответствующие параметры клавиатурных сообщений WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_CHAR.

Параметр wParam содержит код виртуальной клавиши, соответствующей нажатой физической клавише. Именно этот параметр используется приложениями для идентификации нажатой клавиши.

Приведем описание отдельных бит парамера lParam, через который передается дополнительная информация о клавиатурном сообщении .

Бит Описание
0-15 Счетчик повторов. Если нажать клавишу и держать ее в нажатом состоянии, несколько сообщений WM_KEYDOWN и WM_SYSKEYDOWN будут слиты в одно. Количество объединенных таким образом сообщений
16-23 OEM скан-код клавиши. Изготовители аппаратуры (OEM — Original Equipment Manufacturer) могут заложить в своей клавиатуре различное соответствие скан-кодов и обозначений клавиш. Скан-код генерируется клавиатурным контроллером. Это тот самый код, который получают в регистре AH программы MS-DOS, вызывая прерывание INT16h
24 Флаг расширенной клавиатуры. Этот бит установлен в 1, если сообщение соответствует клавише, имеющейся только на расширенной 101- или 102-клавишной клавиатуре. Это может быть одна из следующих клавиш: , ,


, , , клавиши дополнительной клавиатуры.

25-26 Не используются
27-28 Зарезервированы для использования Windows
29 Код контекста. Этот бит равен 1, если сообщение соответствует комбинации клавиши с любой другой, и 0 в противном случае
30 Предыдущее состояние клавиши. Если перед приходом сообщения клавиша, соответствующая сообщению, была в нажатом состоянии, этот бит равен 1. В противном случае бит равен 0
31 Флаг изменения состояния клавиши (transition state). Если клавиша была нажата, бит равен 0, если отпущена — 1

При помощи этого фильтра приложение может удалить клавиатурное сообщение. Для удаления сообщения функция фильтра должна вернуть значение 1. Если же возвращенное значение будет равно 0, сообщение будет обработано системой.

Фильтр WH_MOUSE

Фильтр WH_MOUSE получает управление, когда функции GetMessage или PeekMessage возвращают сообщения мыши. Функция фильтра должна находиться в DLL-библиотеке.

Приведем прототип функции фильтра типа WH_MOUSE:

Так же, как и для предыдущего фильтра, параметр code может принимать значения HC_ACTION и HC_NOREMOVE.

Параметр wParam содержит код сообщения, поступившего от мыши.

Через параметр lParam передается указатель на структуру MOUSEHOOKSTRUCT :

Эта структура содержит дополнительную информацию, имеющую отношение к сообщению.

Поле pt является структурой типа POINT, в которой находятся экранные x- и y-координаты курсора мыши. Поле hwnd содержит идентификатор окна, в функцию которого будет направлено сообщение. В поле wHitTestCode находится код тестирования, определяющий область окна, соответствующую расположению курсора мыши на момент генерации сообщения. Поле dwExtraInfo содержит дополнительную информацию, которую можно получить с помощью функции GetMessageExtraInfo :

Назначение отдельных бит возвращаемого этой функцией значения зависит от аппаратного обеспечения.

Фильтр WH_MSGFILTER

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

Приведем прототип функции фильтра типа WH_MSGFILTER:

Параметр code может принимать значения MSGF_DIALOGBOX (ввод в диалоговой панели), MSGF_SCROLLBAR (ввод в области полосы просмотра), MSGF_MENU (ввод в меню) или MSGF_NEXTWINDOW (пользователь активизирует следующее окно, нажимая комбинацию клавиш или ).

Если фильтр обрабатывает сообщение, функция фильтра должна вернуть ненулевое значение, если нет — нулевое.

Фильтр WH_SYSMSGFILTER

Фильтр WH_SYSMSGFILTER получает управление, когда диалоговая панель или меню выбирает сообщение. Функции фильтра разрешается изменить или обработать перехваченное сообщение. Фильтр WH_SYSMSGFILTER может находиться только DLL-библиотеке. Назначение этого фильтра аналогично назначению фильтра WH_MSGFILTER, но он может быть установлен только для всей системы в целом.

Приведем прототип функции фильтра типа WH_SYSMSGFILTER:

Если фильтр обрабатывает сообщение, функция фильтра должна вернуть ненулевое значение, если нет — нулевое.

Приложение может установить одновременно фильтры WH_SYSMSGFILTER и WH_MSGFILTER, в этом случае вначале вызывается фильтр WH_SYSMSGFILTER, а затем — фильтр WH_MSGFILTER. Если же функция фильтра WH_SYSMSGFILTER возвращает ненулевое значение, фильтр WH_MSGFILTER не вызывается.

Фильтр WH_SHELL

Фильтр WH_SHELL предназначен для приложений-оболочек (shell application) и позволяет получать необходимые извещения от операционной системы Windows.

Приведем прототип функции фильтра типа WH_SHELL:

Параметр code может принимать одно из следующих значений:

Значение параметра code Описание
HSHELL_ACTIVATESHELLWINDOW Оболочка должна активизировать свое главное окно
HSHELL_WINDOWCREATED Создано окно верхнего уровня, которое не принадлежит ни одному приложению. Это окно будет существовать во время работы функции фильтра. Идентификатор созданного окна передается через параметр wParam
HSHELL_WINDOWDESTROYED Описанное выше окно верхнего уровня будет уничтожено после завершения работы функции фильтра. Идентификатор уничтожаемого окна передается через параметр wParam

Функция фильтра должна вернуть нулевое значение.

3.7. Приложение WINHOOK

Когда в нашей стране впервые появилась операционная система Microsoft Windows, она не могла работать с символами кириллицы. Поэтому наши программисты создали несколько приложений, исправляющих этот недостаток.

Для того чтобы Windows стала «понимать» русские символы, необходимо решить несколько задач.

Во-первых, клавиатура персонального компьютера IBM PC не предназначена для ввода символов кириллицы. В операционной системе MS-DOS эта проблема решалась с помощью резидентных программ, перехватывающих аппаратное прерывание от клавиатуры и заменяющих коды символов. Для операционной системы Microsoft Windows этот способ непригоден, так как для работы с клавиатурой используется специальный драйвер.

Во-вторых, необходимо обеспечить отображение символов кириллицы на экране монитора. В MS-DOS для отображения символов кириллицы в текстовом режиме можно было выполнить загрузку таблиц знакогенератора, расположенных в памяти видеоконтроллера. Операционная система Windows не использует текстовый режим, и, соответственно, не использует таблицы знакогенератора. Зато для нее предусмотрен механизм шрифтов различного типа — матричных, векторных и масштабируемых. Очевидно, что единственный способ отображения символов кириллицы в среде Windows — это подготовка версий шрифтов с кириллицей.

В-третьих, необходимо обеспечить правильную работу таких функций, как OemToAnsi и AnsiToOem. Эти функции должны выполнять преобразования, учитывая кодировку символов, которая сама по себе зависит от национального языка.

Есть и другие проблемы использования кириллицы как во всей системе в целом, так и в отдельных приложениях, например, обеспечение правильного формата даты и времени, сортировка, замена строчных букв на прописные, проверка грамматики и правописания, вставка переносов и т. д. Короче говоря, проблема работы с кириллицей и русским языком в Windows сложнее, чем может показаться на первый взгляд.

В этом разделе мы приведем исходные тексты приложения WINHOOK, которое решает первую из перечисленных выше задач, т. е. обеспечивает ввод с клавиатуры символов кириллицы. Приложение WINHOOK позволяет вам изменять раскладку клавиатуры с используемой по умолчанию на определенную в ресурсах приложения. Переключение раскладки выполняется при помощи левой или правой клавиши . Сразу после запуска приложения включается стандартная раскладка клавиатуры. Если вы нажмете на клавишу три раза, то услышите звуковой сигнал, после чего раскладка клавиатуры меняется на альтернативную и вы можете вводить символы кириллицы.

Приложение WINHOOK создает «непотопляемое» окно, которое располагается над поверхностью любого другого окна в Windows. Вы можете перемещать это окно мышью или изменять его размеры. В зависимости от используемой раскладки клавиатуры в окне отображается одно из двух слов: DEFAULT для стандартной раскладки и CYRILLIC для дополнительной (рис. 3.8).

Рис. 3.8. Главное окно приложения WINHOOK при использовании различных раскладок клавиатуры

Если для работы с кириллицей вы используете такие приложения, как CyrWin или ParaWin, перед запуском приложения WINHOOK их следует либо завершить, либо переключить раскладку клавиатуры на стандартную.

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

Основной файл приложения WINHOOK приведен в листинге 3.9.

Листинг 3.9. Файл winhook/winhook.cpp

После запуска приложения функция WinMain определяет размеры окна DeskTop, которые равны размеру экрана, и создает главное окно приложения в виде временного окна с толстой рамкой для изменения размера без заголовка и системного меню (такое окно имеет стиль WS_POPUPWINDOW | WS_THICKFRAME).

Для того чтобы сделать окно «непотопляемым», а заодно и изменить его размеры, мы вызываем функцию SetWindowPos , передав ей в качестве второго параметра константу HWND_TOPMOST:

Функция SetWindowPos позволяет изменить размеры и расположение окна относительно экрана и относительно других окон:

Для параметра hwndInsertAfter, определяющего расположение окна относительно других окон, можно использовать следующие значения:

Значение Описание
HWND_BOTTOM Окно следует расположить под другими окнами
HWND_TOP Окно будет расположено над другими окнами
HWND_TOPMOST Окно следует расположить над всеми другими окнами, имеющими расположение HWND_TOPMOST
HWND_NOTOPMOST Окно будет расположено над всеми HWND_TOP-окнами, но под окном, имеющим расположение HWND_TOPMOST

Параметры x, y, cx и cy определяют, соответственно, горизонтальное и вертикальное расположение окна, его ширину и высоту.

Параметр fuFlags может принимать следующие значения:

Значение Описание
SWP_DRAWFRAME Следует нарисовать рамку, определенную в классе окна
SWP_HIDEWINDOW Окно будет скрыто
SWP_NOACTIVATE Окно не будет активизировано
SWP_NOMOVE Окно не будет перемещаться, при указании этого флага параметры x и y игнорируются
SWP_NOSIZE Окно не будет изменять свои размеры, параметры cx и cy игнорируются
SWP_NOREDRAW Не следует выполнять перерисовку окна. После перемещения приложение должно перерисовать окно самостоятельно
SWP_NOZORDER Не следует изменять расположение окна относительно других окон, параметр hwndInsertAfter игнорируется
SWP_SHOWWINDOW Отобразить окно

После перемещения и изменения расположения главного окна функция WinMain приложения WINHOOK отображает окно и запускает цикл обработки сообщений.

Функция главного окна приложения во время обработки сообщения WM_CREATE вызывает функцию SetKbHook, которая определена в созданной нами для этого приложения DLL-библиотеке kbhook.dll (исходные тексты этой библиотеки будут приведены ниже). Функция SetKbHook устанавливает два фильтра — типа WH_KEYBOARD и WH_GETMESSAGE. В качестве параметра этой функции передается идентификатор главного окна приложения WINHOOK. Когда пользователь переключает раскладку клавиатуры, DLL-библиотека, пользуясь этим идентификатором, пришлет в функцию окна приложения WINHOOK сообщение с кодом WM_KBHOOK.

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

В функции главного окна предусмотрен обработчик сообщения WM_NCHITTEST, позволяющий перемещать окно, не имеющее заголовка. Мы уже использовали аналогичный прием в приложении TMCLOCK, описанном в 11 томе «Библиотеки системного программиста».

Перед завершением работы приложение WINHOOK удаляет установленные ранее фильтры, для чего при обработке сообщения WM_DESTROY вызывается функция RemoveKbHook, определенная в DLL-библиотеке kbhook.dll.

Обработчик сообщения WM_KBHOOK, определенного в нашем приложении и в DLL-библиотеке, определяет номер используемой раскладки клавиатуры через параметр wParam. Полученное значение записывается в переменную флагов раскладки bCyrillic. Если этот флаг сброшен, используется стандартная раскладка клавиатуры, если установлен — дополнительная с символами кириллицы.

После определения раскладки обработчик сообщения WM_KBHOOK выдает звуковой сигнал и перерисовывает главное окно приложения, вызывая функцию InvalidateRect.

Перерисовку окна выполняет обработчик сообщения WM_PAINT. С помощью функции DrawText он пишет название раскладки клавиатуры (DEFAULT или CYRILLIC) в центре главного окна приложения.

Сообщение WM_KBHOOK определено в include-файле winhook.hpp (листинг 3.10).

Листинг 3.10. Файл winhook/winhook.hpp

Код этого сообщения получается при помощи сложения константы WM_USER и числа 1000 (вы можете выбрать другое число в диапазоне от 0 до 0x7fff).

Константа WM_USER специально предназначена для определения приложениями своих собственных кодов сообщений. Если приложение определит свое собственное сообщение и его код будет находиться в пределах от WM_USER до WM_USER + 0x7fff, код такого сообщения не будет конфликтовать с кодами сообщений операционной системы Windows.

Файл определения модуля приложения WINHOOK приведен в листинге 3.11.

Листинг 3.11. Файл winhook/winhook.def

Теперь займемся DLL-библиотекой kbhook.dll, предназначенной для совместной работы с приложением WINHOOK. Исходный текст этой библиотеки представлен в листинге 3.12.

Листинг 3.12. Файл winhook/kbhook.cpp

Функция LibMain, выполняющая инициализацию DLL-библиотеки, после инициализации сегмента данных, запоминает идентификатор модуля DLL-библиотеки, переданный ей через параметр hInstance, в глобальной переменной hinst.

Затем эта функция находит, загружает в память и фиксирует две таблицы, необходимые для использования дополнительной раскладки клавиатуры. Первая таблица загружается из ресурса «XlatTable». Она содержит таблицу перекодировки кодов виртуальных клавиш в ANSI-коды русских строчных букв. Вторая таблица загружается из ресурса «XlatTableCaps» и содержит таблицу перекодировки кодов виртуальных клавиш в ANSI-коды русских прописных букв.

После загрузки и фиксирования адреса таблиц записываются в глобальные переменные с именами lpXlatTable и lpXlatTableCaps.

Так как перекодировка кодов виртуальных клавиш в ANSI-коды должна выполняться с учетом состояния клавиши , для упрощения перекодировки функция LibMain устанавливает эту клавишу в выключенное состояние, пользуясь функциями GetKeyboardState и SetKeyboardState :

Указанные функции, а также использованный способ изменения состояния клавиш был описан в 11 томе «Библиотеки системного программиста».

Функция WEP выполняет расфиксирование и освобождение ресурсов, вызывая функции UnlockResource и FreeResource.

Для установки фильтров в нашей DLL-библиотеки определена функция SetKbHook:

При определении этой функции мы использовали ключевые слова extern «C», в результате чего транслятор C++ не выполняет преобразование имени функции в соответствии с типом ее параметров и типом возвращаемого значения.

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

Функция SetKbHook устанавливает два фильтра — типа WH_KEYBOARD и типа WH_GETMESSAGE. Оба фильтра встраиваются для всей системы в целом, так как последний параметр функции SetWindowsHookEx указан как NULL.

После встраивания фильтров устанавливается флаг bHooked, в глобальную переменную hwndClient записывается идентификатор окна, переданного функции SetKbHook в качестве параметра. Приложение WINHOOK передает идентификатор своего главного окна, пользуясь которым фильтр, расположенный в DLL-библиотеке, будет посылать приложению WINHOOK сообщение WM_KBHOOK.

Для удаления фильтров в DLL-библиотеке определена функция RemoveKbHook:

Эта функция проверяет состояние флага bHooked, и, если фильтры были установлены, удаляет их, вызывая для каждого фильтра функцию UnhookWindowsHookEx.

Функция фильтра типа WH_KEYBOARD пропускает через себя все клавиатурные сообщения, определяя момент, когда пользователь нажмет подряд три раза клавишу .

Как только это произошло, функция фильтра инвертирует флаг bCyrillic и посылает приложению WINHOOK сообщение WM_KBHOOK. В качестве параметра wParam посылаемого сообщения используется значение флага bCyrillic, что позволяет определить приложению номер используемой раскладки клавиатуры:

Фильтр типа WH_MSGFILTER расположен в функции MsgHookProc.

Если перехвачено сообщение WM_KEYDOWN, фильтр проверяет номер используемой раскладки клавиатуры. Если используется стандартная раскладка клавиатуры, сообщение «пропускается» через фильтр без изменений. Для дополнительной раскладки клавиатуры выполняется проверка кода виртуальной клавиши.

Если этот код соответствует клавишам русских букв или цифр в верхнем ряду клавиатуры, фильтр преобразует сообщение WM_KEYDOWN в сообщение WM_CHAR, пользуясь таблицами перекодировок, загруженным из ресурсов DLL-библиотеки. При этом учитывается состояние клавиш и . Для определения состояния переключающих клавиш мы использовали функцию GetKeyState.

Таблицы перекодировки для прописных и строчных букв описаны в файле ресурсов DLL-библиотеки (листинг 3.13).

Листинг 3.13. Файл winhook/kbhook.rc

Файл определения модуля DLL-библиотеки приведен в листинге 3.14.

Листинг 3.14. Файл winhook/kbhook.def

С помощью этого файла экспортируются функции SetKbHook и RemoveKbHook, предназначенные, соответственно, для установки и удаления фильтров, а также функции фильтров KbHookProc и MsgHookProc.

Динамически подключаемая библиотека — Dynamic-link library

Динамически подключаемая библиотека
Имя файла расширения .dll
Интернет-тип носителя application/vnd.microsoft.portable-executable
Равномерное идентификатор типа (ИМП) com.microsoft.windows-динамически подключаемая библиотека
Магическое число MZ
Разработан Microsoft
Контейнер для Общая библиотека

Библиотека динамической компоновки (или DLL ) является Microsoft реализация «s из общей библиотеки концепции в Microsoft Windows и OS / 2 операционные системы . Эти библиотеки обычно имеют расширение файла DLL , OCX (для библиотек , содержащих ActiveX элементов управления), или DRV (для устаревших системных драйверов ). Форматы файлов для библиотек DLL такие же , как для Windows , EXE — файлов — то есть, Portable Executable (PE) для 32-битной и 64-битной Windows, и New Executable (NE) для 16-разрядной Windows. Как EXEs, библиотеки DLL могут содержать код , данные и ресурсы , в любой комбинации.

Данные файлы с тем же форматом файла , как DLL, но с разными расширениями файлов и , возможно , содержащие только разделы ресурсов, можно назвать библиотеки ресурсов . Примеры таких библиотек DLL , включают значок библиотеки , иногда имеющее расширение ICL и шрифты файлы, имеющие расширения FON и FOT .

содержание

Фон для DLL

Первые версии Microsoft Windows запускали программы в едином адресном пространстве . Каждая программа должна была сотрудничать, уступая процессор других программ так , что графический пользовательский интерфейс (GUI) может многозадачность и быть максимально отзывчивыми. Все операции на уровне операционной системы были предоставлены базовой операционной системы: MS-DOS . Все услуги высокого уровня были представлены ОС Windows Libraries «Dynamic Link Library». Drawing API , интерфейс графических устройств (GDI), был реализован в DLL называется GDI.EXE , пользовательский интерфейс в USER.EXE . Эти дополнительные слои поверх DOS должны были быть общими для всех запущенных программ для Windows, а не только для того, чтобы Windows , работать в машине с менее мегабайта оперативной памяти, но для того, чтобы программы сотрудничать друг с другом. Код в GDI нужно перевести команды рисования для операций на определенных устройствах. На дисплее, оно должно было манипулировать пикселей в буфере кадра. При рисовании на принтер, API вызовы должны были быть преобразованы в запросы к принтеру. Несмотря на то, что могло бы быть возможным обеспечить жесткий кодированный поддержку ограниченного набора устройств (например , в цветной графический адаптер дисплея, HP LaserJet Printer Command Language ), Microsoft выбрал другой подход. GDI будет работать при загрузке различных частей кода, называемых « драйверов », для работы с различными устройствами вывода.

Та же архитектурная концепция, которая позволила GDI для загрузки различных драйверов устройств является то, что позволило оболочке Windows, чтобы загрузить различные программы для Windows, и для этих программ для вызова API вызовов из общего ПОЛЬЗОВАТЕЛЯ и библиотек GDI. Эта концепция была «динамическое связывание».

В обычной неразделяемой «статической» библиотеке, фрагменты коды просто добавляются к вызывающей программе, когда его исполняемый файл построен на «связывающую» фазе; если две программы называют ту же процедуру, процедура включена в обоих программах во время стадии зацепления двух. При динамической компоновке, общий код помещается в один отдельный файл. Программы, которые называют этот файл подключены к нему во время выполнения, с операционной системой (или, в случае ранних версий Windows, ОС-расширение), выполняя связывание.

Для этих ранних версий Windows , (1,0 3,11), что библиотеки DLL является основой для всего графического интерфейса. Таким образом , драйверы дисплея были просто DLL файлы с расширением .DRV , что при условии пользовательские реализации одного и того же чертежа API через единый драйвер устройства интерфейса (DDI), и чертеж (GDI) и GUI (USER) интерфейсы были всего лишь вызовы функции , экспортируемые по GDI и USER, системных библиотек DLL с расширением .EXE.


Это понятие построения операционной системы из набора динамически загружаемых библиотек является ключевой концепцией Windows , которая сохраняется от 2015. библиотек DLL предоставляют стандартные преимущества разделяемых библиотек , такие как модульность . Модульность позволяет вносить изменения в код и данные в одном самодостаточного DLL совместно несколькими приложениями без каких — либо изменений в самих приложениях.

Еще одно преимущество модульности является использование общих интерфейсов для плагинов. Единый интерфейс может быть разработан , который позволяет как старые, так и новые модули , которые будут интегрированы во время выполнения в уже существующих приложений, без каких — либо изменений в самом приложении. Эта концепция динамической растяжимости берется до крайности с моделью компонентных объектов , основами ActiveX .

В Windows 1.x, 2.x и 3.x, все приложения Windows , одни и то же адресное пространство, а также ту же память. Библиотеки DLL была загружена только один раз в этом адресное пространство; с тех пор, все программы , использующие библиотеку к нему доступ. Данные библиотеки были общими для всех программ. Это может быть использовано в качестве косвенной формы связи между процессами , или он может случайно повреждать разные программы. С введением 32-битных библиотек в Windows 95 каждый процесс выполняется в своем собственном адресном пространстве. Хотя код DLL может использоваться совместно, данные частная кроме случаев , когда общие данные явно просили библиотеку. Это сказал, большой обматывает Windows 95 , Windows 98 и Windows Me были построены из 16-битных библиотек, которые ограничивают производительность Pro Pentium микропроцессора при запуске, и в конечном итоге ограничивает стабильность и масштабируемость DOS на основе версий Windows.

Хотя библиотеки DLL являются ядром архитектуры Windows, они имеют ряд недостатков, под общим названием « DLL ад ». В 2015 году Microsoft продвигает .NET Framework в качестве одного из решения проблем DLL ад, хотя теперь они продвигают решение виртуализации на основе таких как Microsoft Virtual PC и виртуализация приложений Microsoft , потому что они обеспечивают превосходную изоляцию между приложениями. Альтернативное решение смягчающим к DLL ад реализует бок о бок в сборе .

Особенности DLL

Так как библиотеки DLL, по существу, такой же, как EXEs, выбор которых для производства, как часть процесса связывания для ясности, так как можно экспортировать функции и данные из любого.

Это не представляется возможным непосредственно выполнить DLL, так как он требует EXE для операционной системы, чтобы загрузить его через точку входа, следовательно, существование таких утилит, как rundll.exe или rundll32.exe, которые обеспечивают точку входа и минимальные рамки для библиотек DLL которые содержат достаточное количество функциональных возможностей для выполнения без особой поддержки.

Библиотеки DLL предоставляют механизм для общего кода и данных, что позволяет разработчику совместно используемого кода / данных для обновления функциональных возможностей приложений, не требуя, чтобы быть повторно связаны или повторной компиляции. С точки зрения развития приложений зрения Windows, и OS / 2 можно рассматривать как совокупность библиотек DLL, которые обновляются, позволяя приложения для одной версии операционной системы для работы в более позднем, при условии, что продавец ОС заверил, что интерфейсы и функциональность совместимы.

Библиотеки DLL выполняются в пространстве памяти вызывающего процесса и с теми же правами доступа, что означает, есть немного накладные расходы на их использование, но также, что не существует никакой защиты вызывающего EXE, если DLL имеет какой-либо ошибки.

Управление памятью

В Windows API , что DLL файлы организованы в секции . Каждая секция имеет свой собственный набор атрибутов, такие , как быть доступны для записи или только для чтения, исполняемый файл (для кода) или неисполняемой (для данных), и так далее.

Код в DLL, как правило , распределяется между всеми процессами , которые используют DLL; то есть, они занимают единое место в физической памяти, и не занимают места в файле подкачки . Если физическая память , занимаемая секции коды должны быть утилизирована, его содержимое отбрасывается, а затем перезагружается непосредственно из файла DLL в случае необходимости.

В отличие от участков кода, секции данных о виде DLL, как правило , частные; то есть, каждый процесс с использованием DLL имеет свою собственную копию всех данных в библиотеках DLL. Необязательно, разделы данных могут быть сделаны общими, позволяя связь между процессами с помощью этой общей области памяти. Однако, поскольку ограничения пользователя не распространяются на использование совместно используемой памяти DLL, это создает дыру в безопасности ; а именно, один процесс может развратить общие данные, которые, вероятно , вызывают все другие процессы обмена вести себя нежелательный. Например, процесс выполняется под учетной записью гостя может таким образом коррумпированные другой процесс , работающий под привилегированной учетной записью. Это важная причина , чтобы избежать использования общих разделов в библиотеках DLL.

Если DLL сжимают некоторых упаковщиков исполняемых файлов (например , UPX ), все его кодовых секций помечаются как читать и писать, и будет неразделенная. Для чтения и запись разделов коды, так же, как частные разделы данных, являются частными для каждого процесса. Таким образом , библиотеки DLL с общими разделами данных не должны быть сжаты , если они предназначены для использования одновременно с несколькими программами, поскольку каждый экземпляр программы должен нести свою собственную копию библиотеки DLL, что приводит к увеличению потребления памяти.

Импорт библиотеки

Как статические библиотеки, библиотеки импорта для DLL , отмечены расширением .lib файла. Например, kernel32.dll , первичная динамическая библиотека для базовых функций Windows’ , таких как создание файлов и управление памятью, связана через kernel32.lib.

Связывание с динамическими библиотеками обычно обрабатываются путем связывания с библиотекой импорта при создании или ссылок для создания исполняемого файла. Затем создается исполняемый файл содержит таблицу адресов импорта (IAT), посредством которого ссылаются все вызовы функций DLL (каждая ссылка функция DLL содержит свою собственную запись в IAT). Во время выполнения, то IAT заполняется соответствующими адресами, которые указывают непосредственно на функцию в отдельно загруженной DLL.

Разрешение Символ и связывание

Каждая функция экспортируется в DLL идентифицируется числовым порядкового и необязательно именем. Кроме того, функции могут быть импортированы из DLL либо по порядковому номеру или по имени. Порядковые представляет положение указателя адреса функции в таблице DLL Export Address. Он является общим для внутренних функций, которые будут экспортироваться по порядковому только. Для большинства функций Windows API, только имена сохраняются в различных выпусках Windows; ординалы могут быть изменены. Таким образом, один не может надежно импортировать функции Windows API, их порядковые.

Импорт функций по порядковому номеру обеспечивает только немного лучшую производительность , чем импортировать их по именам: экспорт таблицы библиотек DLL упорядочены по имени, поэтому бинарный поиск может быть использован , чтобы найти функцию. Индекс найденного имени затем используется для поиска порядковых в таблице экспорт Порядковой. В 16-битной Windows, таблица имя не отсортирован, поэтому накладные расходы поиск имени был гораздо более заметным.

Кроме того , можно связать исполняемый файл для конкретной версии DLL, то есть, чтобы разрешить адреса импортируемых функций во время компиляции. Для связанного импорта, компоновщик сохраняет временные метки и контрольную сумму DLL , в которой импорт связан. Во время выполнения Windows , проверяет , является ли та же версия библиотеки используются, и если да, Windows обходит обработку импорта. В противном случае, если библиотека отличается от той , которая была связана с, Windows обрабатывает импорт в обычном порядке.

Связанные Исполняемые нагрузки несколько быстрее , если они работают в той же среде , что они были составлены для, и точно то же самое время , если они работают в другой среде, поэтому нет никаких недостатков для связывания импорта. Например, все стандартные приложения Windows , связаны с системным DLL , их соответствующего выпуска Windows. Хорошая возможность связать Импортирует приложения к целевой среде во время установки приложения. Это позволяет «связанно» до следующего обновления операционной системы библиотек. Это, однако, изменить контрольную сумму исполняемого файла, так что это не то , что может быть сделано с подписанными программ или программ, которые управляются с помощью инструмента управления конфигурацией , которая использует контрольные суммы (например, MD5 контрольных сумм) для управления версиями файлов. В более поздние версии Windows , отошли от того , фиксированных адресов для каждой загружаемой библиотеки (по соображениям безопасности), возможность и стоимость связывания исполняемый уменьшаются.

Явное время выполнения связывания

DLL — файлы могут быть загружены явно во время выполнения, процесс называют просто времени выполнения динамического связывания с помощью Microsoft, используя LoadLibrary (или LoadLibraryEx ) функции API. GetProcAddress Функция API используется для просмотра экспортированных символов по имени, FreeLibrary — выгрузить DLL. Эти функции аналогичны dlopen , dlsym и dlclose в POSIX стандарта API.

Процедура явного времени выполнения связывания является одинаковой в любом языке , который поддерживает указатели на функцию , так как это зависит от интерфейса Windows API , а не языковых конструкций.

Задержка загрузки

Как правило, это приложение , которое было связано с библиотекой импортировать библиотеки DLL не запустится , если DLL не может быть найден, поскольку не будет запускать приложение , если оно не может найти все библиотеки DLL , что приложение может понадобиться. Однако приложение может быть связанно с библиотекой импорта , чтобы задержанная загрузкой динамической библиотеки. В этом случае операционная система не будет пытаться найти или загрузить DLL при запуске приложения; вместо заглушки входят в приложении с помощью линкера , который будет пытаться найти и загрузить DLL через LoadLibrary и GetProcAddress , когда одна из его функций называются. Если DLL не может быть найдено или загружено, или вызываемая функция не существует, то приложение будет генерировать исключение , которое может быть зафиксировать и обработать соответствующим образом . Если приложение не обрабатывает исключение, оно будет поймано операционной системой, которая будет завершать работу программы с сообщением об ошибке.

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

Компилятор и язык соображения

Delphi

В исходном файле ключевое слово library используется вместо program . В конце файла, функции должны быть экспортированы, перечислены в exports п.

Delphi не нужны LIB файлы импортировать функции из библиотеки DLL; связать с DLL, то external используется ключевое слово в объявлении функции для сигнализации имени DLL, а затем name назвать символ (если отличается) или index для идентификации индекса.

Microsoft Visual Basic

В Visual Basic (VB), только время выполнения связывания поддерживается; но в дополнении к использованию LoadLibrary и GetProcAddress функциям API, декларации импортируемых функций допускаются.

При импорте функции DLL через декларации, VB будет генерировать ошибку времени выполнения , если DLL файл не может быть найден. Разработчик может поймать ошибку и обработать его соответствующим образом .

При создании библиотеки DLL в VB, среда только позволит вам создавать DLL-библиотеки ActiveX, однако методы были созданы, чтобы позволить пользователю явно указать линкер включить файл .DEF который определяет порядковый номер и название каждой экспортируемой функции. Это позволяет пользователю создавать стандартный Windows DLL с помощью Visual Basic (версия 6 или ниже), которые можно ссылаться через «Объявлять» заявление.

C и C ++

Microsoft Visual C ++ (MSVC) предоставляет несколько расширений для стандартного C ++ , которые позволяют функции , которые будут определены как импортированы или экспортированы непосредственно в коде C ++; они были приняты другими ОС Windows Си компиляторов и C ++, включая версии Windows , в GCC . Эти расширения используют атрибут __declspec перед объявлением функции. Обратите внимание , что , когда функция C доступна из C ++, они также должны быть объявлены как extern «C» в коде C ++, чтобы сообщить компилятору , который следует использовать С связью.

Кроме указания импортируемых или экспортируемых функций , используя __declspec атрибуты, они могут быть перечислены в IMPORT или экспортирование части DEF файла , используемого в проекте. DEF Файл обрабатывается с помощью линкера, а не компилятор, и таким образом это не является специфической для C ++.

DLL компиляция будет производить как DLL и LIB файлы. LIB Файл используется для связывания против DLL во время компиляции; это не является необходимым для выполнения временных связей. Если ваша DLL не является Component Object Model сервер (COM), то DLL файл должен быть помещен в один из каталогов , перечисленных в переменной PATH среды, в каталоге системы по умолчанию, или в том же каталоге, что и программа его использования. Библиотеки DLL COM — сервера регистрируются с помощью regsvr32.exe, который помещает местоположение DLL и ее глобально уникальный идентификатор ( GUID ) в реестре. Программы могут затем использовать DLL, отыскав его GUID в реестре , чтобы найти его местоположение или создать экземпляр COM — объекта косвенно , используя свой идентификатор класса и идентификатор интерфейса.

примеры программирования

Использование импорта DLL

Следующие примеры показывают, как использовать специфические для языка привязки импортировать символы для связывания против DLL во время компиляции.

Убедитесь , что Вы Example.lib файл (при условии , что Example.dll генерируется) в проекте (Добавить существующий вариант предмета для проекта!) До статического связывания. Файл Example.lib автоматически генерируется компилятором при компиляции DLL. Не выполнив выше заявления вызовет ссылки ошибки компоновщика не будет знать , где найти определение AddNumbers. Кроме того, необходимо скопировать DLL Example.dll в то место , где .exe файл будет сгенерирован следующим кодом.

Используя явное время выполнения связывания

Следующие примеры показывают, как использовать во время выполнения загрузки и связывания объектов с использованием конкретного языка привязок API Windows.

Microsoft Visual Basic

Внимание: следующий код уязвим, он не соответствует руководства Microsoft для безопасной загрузки библиотеки!

Delphi

Внимание: следующий код уязвим, он не соответствует руководства Microsoft для безопасной загрузки библиотеки!

Внимание: следующий код уязвим; она не соответствует указаниям от Microsoft для безопасной загрузки библиотеки.

питон

Внимание: следующий код уязвим; она не соответствует руководства Microsoft для безопасной загрузки библиотеки!

Модели компонентных объектов

Модели компонентных объектов (COM) определяет двоичный стандарт для размещения реализации объектов в DLL и EXE — файлов. Он предоставляет механизмы для обнаружения и версию этих файлов, а также независимое от языка и машиночитаемого описание интерфейса. Хостинг COM объектов в DLL является более легким и позволяет им обмениваться ресурсами с клиентским процессом. Это позволяет COM — объекты реализовать мощные обратные концы простой графический интерфейс интерфейсам , таких как Visual Basic и ASP. Они также могут быть запрограммированы с языками сценариев.

DLL угон

Из — за уязвимости , известные как DLL угон, DLL подмена, DLL предзагрузка двоичных или посадки, многие программы будут загружать и выполнять вредоносный DLL , содержащийся в той же папке, что и файл данных открыт эти программы. Уязвимость была обнаружена Георгием Guninski в 2000 г. В августе 2010 года она получила всемирную известность после того, как безопасность ACROS вновь его снова и многие сотни программ были признаны уязвимыми. Программы, которые запускаются из ненадежных местах, то есть пользовательские папки для записи , как в Загрузки или Temp каталога, почти всегда подвержены этой уязвимости.

DynLib: библиотека для создания и работы с DLL

Библиотека DynLib предоставляет удобные средства для разработчиков, использующих межмодульное взаимодействие (EXE DLL, DLL DLL) в своих проектах, и значительно сокращает время и количество кода.
DynLib стала неотъемлемым инструментом разработки. Под катом делимся результатами.

Недостатки традиционного подхода к реализации DLL

Примеры использования DynLib

1. Использование обычной DLL

Задача. Динамически подключить и использовать библиотеку test_lib.dll, реализующую простые математические операции, с интерфейсом, представленным в заголовочном файле:
Решение. Необходимо написать следующий заголовочный файл и подключить его к проекту.
Препроцессор сгенерирует класс test::lib, выполняющий динамическую загрузку DLL и содержащий перечисленные функции sum, mul и epsilon. Для подключения DLL к приложению необходимо включить представленный заголовочный файл test_lib.hpp в исходный код. Далее следует создать объект класса test::lib. Доступ к экспортируемых функциям DLL возможен через ‘.’ или ‘->’.

2. Создание библиотеки calculator.dll

Задача. Написать библиотеку calculator.dll, которая должна вычислять сумму, произведение двух чисел и значение квадратного корня. Динамически загрузить библиотеку и вызвать каждую функцию.
Решение

3. Модернизация библиотеки calculator.dll. Использование исключений.

Задача. Функция вычисления квадратного корня sqrt в библиотеке calculator.dll должна возвращать ошибку в случае некорректного входного значения.
Решение

4. Реализация библиотеки shapes.dll. Использование интерфейсов.

Задача. Создать библиотеку shapes.dll по работе с геометрическими фигурами (квадрат, прямоугольник, круг). Все фигуры должны поддерживать общий интерфейс, через который можно узнать координаты центра фигуры.
Решение

Как подключить библиотеку

Библиотека поставляется в виде заголовочных файлов. Никаких .lib и .dll не требуется. Для подключения требуется добавить следующую директиву:

Элементы библиотеки

Многие классы и макросы библиотеки DynLib могут использоваться самостоятельно и отдельно друг от друга.

DL_BLOCK

Служит контейнером для всех остальных макросов.

DL_NS_BLOCK

Служит контейнером для всех остальных макросов. Создает пространства имен для класса.
Макросы, которые описаны ниже кроме DL_EXPORT, должны быть помещены в DL_BLOCK или DL_NS_BLOCK

DL_C_LIBRARY

Назначение макроса — предоставить пользователю готовый класс, реализующий динамическую загрузку DLL и автоматический импорт функций. Макрос представлен как:

  • lib_class — имя класса, реализацию которого генерирует библиотека DynLib;
  • functions — перечисление функций, экспортируемых DLL. задается через список следующего формата
    (ret_type, call, (name, import_name), arguments)
    • ret_type — тип возвращаемого функцией значения;
    • call — формат вызова, например: __sdtcall, __cdecl и т.п.;
    • name — имя функции (для пользователя);
    • import_name — имя функции, заданной в таблице экспорта DLL, включая декорацию (если она есть). Если name и import_name совпадают, то import_name можно не указывать.
    • arguments — список (тип аргумента, имя аргумента, = значение по умолчанию), задающий входные аргументы. Имя аргумента и значение по умолчанию можно не указывать.;

    Пример:

Классы, генерируемые макросом DL_C_LIBRARY, нельзя передавать через границы DLL

DL_RECORD

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

DL_LIBRARY

Макрос DL_LIBRARY выполняет несколько задач:

  1. выступает в роли описания (документирования) интерфейса между EXE(DLL) и DLL;
  2. содержит необходимые структуры для автоматического экспорта функций библиотеки для разработчика;
  3. реализует класс, обеспечивающий загрузку DLL с заданным интерфейсом и предоставляющий доступ к экспортируемым функциям со стороны пользователя;
  4. обеспечивает корректное использование C++ исключений:

Классы, генерируемые макросом DL_LIBRARY, нельзя передавать через границы DLL.
Для демонстрации работы макроса представим следующий заголовочный файл:
Данное описание используется разработчиком DLL для экспорта функций посредством макроса DL_EXPORT. Пользователь, подключив заголовочный файл test1_lib.hpp, может сразу начать работу с DLL:

DL_EXPORT

Макрос DL_EXPORT предназначен для экспортирования функций DLL.
DL_EXPORT(lib_class, lib_impl_class)

  • lib_class — полное имя класса, описывающего интерфейс взаимодействия (то имя класса, что использовалось в DL_LIBRARY);
  • lib_impl_class — полное имя класса класса, РЕАЛИЗУЮЩЕГО функции, указанные в интерфейсе взаимодействия.

Для экспорта функций DLL необходимо:

  1. Создать класс (структуру);
  2. Определить каждую функцию из интерфейса как статическую. Функции должны находиться в области видимости public:;
  3. Произвести экспорт функций, написав конструкцию DL_EXPORT(lib, impl).

Для примера, представим реализацию DLL для интерфейса взаимодействия в файле test1_lib.hpp, определенного в описании DL_LIBRARY.

DL_INTERFACE

Макрос позволяет описать интерфейс класса и предоставить пользователю класс-обертку для работы с ним. Реализация класса-обертки обеспечивает корректное использование C++ исключений: Класс-обертка, генерируемая данным макросом, имеет разделяемое владение объектом, реализующего данный интерфейс. Разделяемое владение обеспечивается механизмом подсчета ссылок, т.е. когда происходит копирование объектов класса-обертки, вызывается внутренняя функция для увеличения счетчика ссылок, при уничтожении — внутренняя функция по уменьшению счетчика ссылок. При достижении счетчиком значения 0 происходит автоматическое удаление объекта. Доступ к методам интерфейса осуществляется через ‘.’ или ‘->’.
Библиотека DynLib гарантирует безопасное использование классов-интерфейсов на границе EXE(DLL) DLL

  • interface_class — имя класса, реализацию которого генерирует библиотека DynLib;
  • methods — перечисление функций, описывающих интерфейс класса,

Пример:

dl::shared

Шаблонный класс dl::shared решает следующие задачи:

  1. динамическое создание объекта класса T с аргументами, переданными в конструкторе;
  2. добавление счетчика ссылок и обеспечение разделяемого владения (подобно boost(std)::shared_ptr);
  3. неявное приведение к объекту класса, генерируемого макросом DL_INTERFACE.

Доступ к членам-функциям класса T осуществляется через ‘->’.
Классы dl::shared нельзя передавать через границы DLL.
Предположим, имеется класс my_processor и интерфейс example::processor:

Примеры использования dl::shared представлены ниже:

dl::ref

Функция библиотеки, позволяющая привести любой объект к объекту класса-интерфейса, объявленному через DL_INTERFACE, с идентичным набором методов. Обычно такое поведение необходимо, когда имеется функция, принимающая в качестве аргумента класс-интерфейс, а ему следует передать объект, размещенный в стеке.
Использовать функцию dl::ref нужно с осторожностью, поскольку объекты классов-интерфейсов, в этом случае не будут владеть переданными объектами, а управление временем жизни объекта и его использованием через классы-интерфейсы ложится на пользователя. Копирование объектов классов-интерфейсов, ссылающих на объекты, переданные через dl::ref, разрешено и вполне корректно (поскольку счетчика ссылок нет, то и изменять нечего — объекты классы-интерфейсов знают как здесь корректно работать).

Илон Маск рекомендует:  PAnsiString - Тип Delphi
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL