Джонсон Харт - Системное программирование в среде Windows Страница 43
- Категория: Компьютеры и Интернет / Программирование
- Автор: Джонсон Харт
- Год выпуска: -
- ISBN: -
- Издательство: -
- Страниц: 142
- Добавлено: 2019-05-29 10:43:08
Джонсон Харт - Системное программирование в среде Windows краткое содержание
Прочтите описание перед тем, как прочитать онлайн книгу «Джонсон Харт - Системное программирование в среде Windows» бесплатно полную версию:Эта книга посвящена вопросам разработки приложений с использованием интерфейса прикладного программирования операционных систем компании Microsoft (Windows 9х, Windows XP, Windows 2000 и Windows Server 2003). Основное внимание уделяется базовым системным службам, включая управление файловой системой, процессами и потоками, взаимодействие между процессами, сетевое программирование и синхронизацию. Рассматривается методика переноса приложений, написанных в среде Win32, в среду Win64. Подробно описываются все аспекты системы безопасности Windows и ее практического применения. Изобилие реальных примеров, доступных также и на Web-сайте книги, существенно упрощает усвоение материала.Книга ориентирована на разработчиков и программистов, как высокой квалификации, так и начинающих, а также будет полезна для студентов соответствующих специальностей.
Джонсон Харт - Системное программирование в среде Windows читать онлайн бесплатно
}
CloseHandle(hXFile);
/* Размер отдельной записи. */
return KSize * TSIZE + sizeof(LPTSTR);
}
Динамически компонуемые библиотеки
Как вы имели возможность убедиться, средства управления памятью и отображения файлов оказываются важными и полезными для широкого класса программ. Системы управления памятью используются также самими ОС, и наиболее важной и заслуживающей внимания сферой применения отображения файлов являются библиотеки DLL. DLL широко используются приложениями Windows, являясь существенным элементом таких высокоуровневых технологий, как СОМ, а многие компоненты программного обеспечения поставляются в виде DLL.
Нашим первым шагом будет рассмотрение различных методов построения библиотек наиболее часто используемых функций.
Статические и динамические библиотеки
Самый непосредственный способ построения любой программы — это объединение исходных кодов всех функций, их компиляция и компоновка всех необходимых элементов в один исполняемый модуль. Чтобы упростить процесс сборки, такие функции общего назначения, как ReportError, можно поместить в библиотеку. Этот подход применялся во всех представленных до сих пор примерах программ, хотя и касался всего лишь нескольких функций, большинство из которых предназначались для вывода сообщений об ошибках.
Эта монолитная, одномодульная модель отличается простотой, однако обладает и рядом недостатков.
• Исполняемый модуль может разрастаться до больших размеров, занимая большие объемы дискового пространства и физической памяти во время выполнения и требуя дополнительных усилий для организации управления модулем и передачи его пользователям.
• При каждом обновлении потребуется повторная сборка всей программы, даже если необходимые изменения незначительны или носят локальный характер.
• Каждый исполняемый модуль тех программ в системе, которые используют эти функции, будет иметь свои экземпляры функций, версии которых могут различаться. Подобная схема компоновки приводит к тому, что при одновременном выполнении нескольких таких программ будет напрасно расходоваться дисковое пространство и, что намного существеннее, физическая память.
• Для достижения наилучшей производительности в различных средах может потребоваться использование различных версий программы, в которых применяются различные методики. Так, функция Asc2Un в программе 2.4 (atou) и программе 5.3 (Asc2UnMM) реализована по-разному. Единственный способ выполнения программ, имеющих несколько различных реализаций, — это заранее принять решение относительно того, какую из двух версий запускать, исходя из свойств окружения.
Библиотеки DLL обеспечивают возможность элегантного решения этих и других проблем.
• Библиотечные функции не связываются во время компоновки. Вместо этого их связывание осуществляется во время загрузки программы (неявное связывание) или во время ее выполнения (явное связывание). Это позволяет существенно уменьшить размер модуля программы, поскольку библиотечные функции в него не включаются.
• DLL могут использоваться для создания общих библиотек (shared libraries). Одну и ту же библиотеку DLL могут совместно использовать несколько одновременно выполняющихся программ, но в память будет загружена только одна ее копия. Все программы отображают код DLL на адресные пространства своих процессов, хотя каждый поток будет иметь собственный экземпляр неразделяемого хранилища в стеке. Например, функция ReportError использовалась почти в каждом из приведенных ранее примеров программ, тогда как для всех программ было бы вполне достаточно ее единственной DLL-реализации.
• Новые версии программ или другие возможные варианты их реализации могут поддерживаться путем простого предоставления новой версии DLL, а все программы, использующие эту библиотеку, могут выполняться как новая версия без внесения каких бы то ни было дополнительных изменений.
• В случае явного связывания решение о том, какую версию библиотеки использовать, программа может принимать во время выполнения. Разные библиотеки могут быть альтернативными вариантами реализации одной и той же функции или решать совершенно иные задачи, как если бы они были независимыми программами. Библиотека выполняется в том же процессе и том же потоке, что и вызывающая программа.
Библиотеки DLL, иногда в ограниченном виде, используются практически в любой ОС. Так, в UNIX аналогичные библиотеки фигурируют под названием "разделяемых библиотек" (shared libraries). В Windows библиотеки DLL используются, помимо прочего, для создания интерфейсов ОС. Весь Windows API поддерживается одной DLL, которая для предоставления дополнительных услуг вызывает ядро Windows.
Один код DLL может совместно использоваться несколькими процессами Windows, но после его вызова он выполняется как часть вызывающего процесса или потока, Поэтому библиотека может использовать ресурсы вызывающего процесса, например дескрипторы файлов, и стек потока. Следовательно, DLL должны создаваться таким образом, чтобы обеспечивалась безопасная многопоточная поддержка (thread safety). (Более подробная информация относительно DLL и безопасной многопоточной поддержки содержится в главах 8, 9 и 10. Методы создания DLL, предоставляющих многопоточную поддержку, иллюстрируются программами 12.4 и 12.5.) Кроме того, DLL могут экспортировать переменные, а также точки входа функций.
Неявное связывание
Неявное связывание, или связывание во время загрузки (load-time linking) является простейшей из двух методик связывания. Порядок действий в случае использования Microsoft C++ следующий:
1. После того как собраны все необходимые для новой DLL функции, осуществляется сборка DLL, а не, например, консольного приложения.
2. В процессе сборки создается библиотечный .LIB-файл, играющий роль заглушки (stub) для фактического кода. Этот файл должен помещаться в каталог библиотек общего пользования, указанный в проекте.
3. В процессе сборки создается также .DLL-файл, содержащий исполняемый модуль. В типичных случаях этот файл размещается в том же каталоге, что и приложение, которое будет его использовать, и приложение загружает DLL в процессе своей инициализации. Вторым возможным местом расположения DLL является рабочий каталог, а далее ОС будет осуществлять поиск .DLL-файла в системном каталоге, каталоге Windows, а также в путях доступа, указанных в переменной окружения PATH.
4. В исходном коде DLL следует предусмотреть экспортирование интерфейсов функций, о чем рассказано ниже.
Экспортирование и импортирование интерфейсовСамое значительное изменение, которое требуется внести в функцию, прежде чем ее можно будет поместить в DLL, — это объявить ее экспортируемой (UNIX и некоторые другие системы не требуют явного выполнения этого шага). Это достигается либо за счет использования .DEF-файла, либо, что проще и возможно в Microsoft С, за счет использования в объявлениях модификатора _declspec (dllexport) следующим образом:
_declspec(dllexport) DWORD MyFunction (…);
Далее в процессе сборки создаются .DLL-файл и .LIB-файл. .LIB-файл — это библиотека-заглушка, которая должна быть скомпонована с вызывающей программой для разрешения внешних ссылок и создания актуальных связей с . DLL-файлом во время загрузки.
Вызывающая, или клиентская, программа должна объявить о том, что функцию следует импортировать, используя для этого модификатор _declspec (dllexport). Стандартный метод заключается в создании включаемого файла, использующего переменную препроцессора, имя которой формируется на основе имени проекта Microsoft Visual C++, набранного в верхнем регистре и дополненного суффиксом _EXPORTS.
Вам также может потребоваться еще одно объявление. Если вызывающая (клиентская) программа написана на C++, то для нее будет определена переменная препроцессора __cplusplus, и вы должны будете указать на необходимость использования системы соглашений о вызовах, принятой в С, с помощью следующего выражения:
extern "С"
Если, например, в качестве части сборки DLL в проекте MyLibrary определена функция MyLibrary, то содержимое заголовочного файла должно быть таким:
#if defined(MYLIBRARY_EXPORTS)
#define LIBSPEC _declspec(dllexport)
#elif defined(__cplusplus)
#define LIBSPEC extern "C" _declspec(dllimport)
#else
#define LIBSPEC _declspec(dllimport)
#endif
LIBSPEC DWORD MyFunction (…);
Visual C++ автоматически определяет MYLIBRARY_EXPORTS при вызове компилятора, если проект предназначен для создания DLL MyLibrary. Клиентский проект, который использует DLL, переменную MYLIBRARYEXPORTS не определяет, и поэтому имя функции импортируется из библиотеки.
При построении вызывающей программы укажите соответствующий .DLL-файл. Когда будете запускать вызывающую программу на выполнение, убедитесь в наличии доступа к этому файлу; часто это обеспечивается размещением .DLL-файла в одном каталоге с исполняемым файлом. Как ранее уже отмечалось, существует ряд правил поиска DLL, определяющих последовательность просмотра каталогов, в которых Windows будет осуществлять поиск указанного .DLL-файла, а также других DLL и исполняемых файлов, необходимых указанному файлу, прекращая этот поиск, как только будет найден первый подходящий экземпляр. Ниже приведена стандартная последовательность просмотра каталогов при поиске, используемая как в случае явного, так и в случае неявного связывания.
Жалоба
Напишите нам, и мы в срочном порядке примем меры.