Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

OC Windows & OC Linux. Лабораторные работы по курсу «Операционные системы»

.pdf
Скачиваний:
0
Добавлен:
06.09.2026
Размер:
2 Мб
Скачать
В приведенном выше примере в разделе EXPORTS перечисле­ны имена нескольких экспортируемых функций. Около некоторых имен после символа @ указаны порядковые номера соответствую­щих функций в DLL-библиотеке.
Если вы не укажете порядковые номера экспортируемых функ­ций, при компоновке загрузочного файла DLL-библиотеки редактор связи создаст свою собственную нумерацию, которая может изме­няться при следующей повторной компоновке.
Если при помощи файла определения модуля DLL-библиотеки вы задаете фиксированное распределение порядковых номеров экс­портируемых функций, при внесении изменений в исходные тексты DLL-библиотеки это распределение не изменится. В этом случае все приложения, ссылающиеся на функции из этой библиотеки по порядковым номерам, будут работать правильно. Если же вы не оп­ределили порядковые номера функций, у приложений могут возник­нуть проблемы с правильной адресацией функции из-за возможного изменения этих номеров.
1.3.5. Импортирование функций
Когда вы используете статическую компоновку, то включаете в файл проекта приложения соответствующий lib-файл, содержащий нужную вам держит исполняемый код модулей, который на этапе статической компоновки включается в ехе-файл загрузочного модуля.
Если используется динамическая компоновка, в загрузочный ехе-файл приложения записывается не исполнимый код функций, а ссылка на соответствующую DLL-библиотеку и функцию внутри нее. Как мы уже говорили, эта ссылка может использованием либо имени функции, либо ее порядкового номера в DLL-библиотеке.
С помощью оператора IMPORT можно перечислить импорти­руемые функции, указав имена функций или их порядковые номера, а также имена файлов соответствующих DLL-библиотек:
IMPORTS
Msg=dllsrc.4
dllsrc.TelIMe
внесении изменений в исходные тексты функций и по-
их
библиотеку объектных модулей. Такая библиотека со-
быть организована с
61
Во второй строке приведенного выше примера приложение им­портирует функцию Msg из DLL-библиотеки dllsrc.dll, причем по­рядковый номер указанной функции в библиотеке равен 4.
В третьей строке из DLL-библиотеки dllsrc.dll импортируется функция с именем TelIMe, причем ее порядковый номер не исполь­зуется.
Для увеличения скорости работы приложения рекомендуется использовать способ, основанный на ссылке по имени DLL-библи отеки и порядковому номеру функции внутри этой библиотеки.
1.3.6. Файл определения модуля для DLL-библиотеки
Файл определения модуля для DLL-библиотеки отличается от соответствующего файла обычного приложения Windows. В качест­ве примера приведем образец такого файла:
LIBRARY DLLNAME
DESCRIPTION 'DLL-библиотека DLLNAME'
EXETYPE windows
CODE moveable discardable
DATA moveable single
HEAPSIZE 1024
EXPORTS
DrawBitmap @4
ShowAll
HideAll
GetMyPool @8
FreeMyPool @9
В файле определения модуля DLL-библиотеки вместо операто­ра NAME должен находиться оператор LIBRARY, определяющий имя
модуля DLL-библиотеки, под которым она будет известна Win-
dows.
Остальные операторы те же, что и для обычного приложения, за исключением того, что в файле определения модуля DLL-библи­отеки не должно быть оператора STACKSIZE (так как у DLL-библи­отеки нет стека).
Оператор CODE используется для определения атрибутов сег­мента кода DLL-библиотеки.
-
62
Особенностью оператора DATA является использование пара­метра SINGLE. Так как DLL-библиотека находится в памяти в един­ственном экземпляре и может иметь только один сегмент данных, для описания сегмента данных библиотеки требуется параметр SINGLE. Оператор HEAPSIZE определяет начальное значение ло­кальной области памяти, которая будет выделена для DLL-библи­отеки функцией LibEntry на этапе инициализации. Если DLL-библи­отека не должна иметь локальную область данных, в качестве пара­метра следует указать нулевое значение:
HEAPSIZE 0
И, наконец, оператор EXPORTS предназначен для перечисления имен и порядковых номеров функций, экспортируемых DLL-библи­отекой.
З
АДАНИЯ НА РАБОТУ
Задание 1. Создать собственную библиотеку динамической ком-
поновки DLL, содержащую функцию из лабораторной работы № 1
Задание 2. Написать программу для вызова функции, располо­женной в DLL-библиотеке, созданной в задании 1 и показывающей работу этой функции.
63
ЛАБОРАТОРНАЯ РАБОТА 5
ОБМЕН ДАННЫМИ ЧЕРЕЗ DDE
Введение
Операционная система Windows предоставляет пользователю возможность запустить одновременно несколько приложений. Как правило, пользователь именно так и поступает. Однако сама по себе эта достаточно важная особенность Windows не имела бы столь большого значения, если бы не существовали удобные механизмы обмена данными между приложениями.
Цель работы: ознакомить
студентов с механизмом динамиче­ского обмена данными DDЕ (Dynamic Data Exchange), позволяющим создавать постоянно действующие каналы между несколькими од­новременно работающими приложениями Windows.
О
ПИСАНИЕ РАБОТЫ
Начиная с версии 3.1 в составе Windows появилось расширение – управляющая библиотека динамического обмена данными DDEML, выполненная как обычная DLL-библиотека. При создании новых DDЕ-приложений в SDK рекомендуется пользоваться именно этой библиотекой, а не старым механизмом, основанным на передаче со­общений. Библиотека DDEML хороша сама по себе, так как она уп­рощает DDЕ-приложения и избавляет
программиста от учета утоми­тельных деталей протокола обмена сообщениями. Однако есть еще две причины, по которым следует пользоваться этой библиотекой.
Во-первых, в новых версиях Windows, а также в операционной системе Windows NT динамический обмен данных организуется ис­ключительно с помощью библиотеки DDEML. Поэтому если в бу­дущем вы собираетесь переносить свое приложение в
среду Win­dows NT или Windows-95, имеет смысл сразу ориентироваться на работу с DDEML.
Во-вторых, вспомним о существовании такой операционной системы, как Windows for Workgroups. Сетевые возможности Win­dows for Workgroups базируются на сетевом динамическом обмене данными Network DDE (операционная система Windows NT также поддерживает Network DDE).
Механизм Network DDE позволяет организовать каналы обмена данными между приложениями, которые запущены на разных рабо-
64
чих станциях сети. Поэтому освоение «обычной» библиотеки DDEML можно считать первым шагом на пути к изучению сетевых возможностей различных версий Windows.
1.1. Архитектура «клиентсервер»
Клиентом и сервером мы будем называть процессы (програм­мы или приложения), работающие одновременно на одном или раз­ных компьютерах (объединенных в сеть), и взаимодействующих между собой определенным
Клиент посылает серверу запрос на получение данных или вы­полнение какой-либо работы. Это может быть запрос к серверу базы данных, задание серверу резервного копирования дисков или что-то аналогичное.
Сервер, получив от клиента запрос, выполняет соответствую­щие действия и посылает клиенту ответ. Например, сервер базы данных находит нужные записи зервного копирования вводит в действие механизм выгрузки данных на магнитную ленту или магнитооптическое дисковое устройство и сообщает клиенту о запуске процедуры.
Процесс передачи запроса серверу называется транзакцией.
Строго говоря, транзакцияэто совокупность трех дейст-
вий: посылка запроса, выполнение запроса, прием ответа.
Транзакция называется завершенной действия. Если же на одном из трех этапов произошел сбой, тран­закция останется незавершенной. После восстановления незавер­шенная транзакция откатывается, что необходимо в ряде случаев для сохранения целостности данных (разумеется, за правильное вы­полнение отката транзакции отвечает сервер).
Например, если сервер базы данных получил от клиента на обновление записей в нескольких файлах и перед аварийным от­ключением электропитания успел выполнить только часть работы, после восстановления ему необходимо восстановить состояние базы данных на момент начала незавершенной транзакции.
Топология системы, имеющей архитектуру «клиент – сервер», может быть различной. В системе может быть несколько клиентов, работающих с одним сервером, или щих одновременно с несколькими серверами.
Приложения, использующие технологию динамического обмена данных DDE, выступают как клиенты или серверы (или одновре-
образом.
и посылает их клиенту. Сервер ре-
, если выполнены все три
запрос
несколько клиентов, работаю-
65
менно как клиенты и серверы). При этом взаимодействие между ни­ми – это ни что иное, как транзакции.
Библиотека DDEML позволяет создавать системы, имеющие различные топологии.
1.2. Инициализация и создание канала связи
Предположим, что нам нужно создать канал связи между двумя одновременно работающими приложениями Windows. Опишем со­ответствующие процедуры при использовании библиотеки DDEML. Пусть одно клиентом.
В процессе инициализации сервер должен выполнить такие действия:
зарегистрировать себя в библиотеке DDEML; – зарегистрировать предоставляемый сервис, которым сможет вос-
пользоваться приложение-клиент.
Клиент должен сделать следующее:
зарегистрировать себя в библиотеке DDEML; – создать канал связи с сервером, указав необходимый сервис.
Рассмотрим эти
1.2.1. Регистрация в библиотеке DDEML
Библиотека DDEML используется одновременно многими при­ложениями, однако, подобно всем DLL-библиотекам, находится в оперативной памяти в единственном экземпляре. Функция LibMain, выполняющая инициализацию DLL-библиотеки, вызывается только один раз при первой загрузке библиотеки в память (для Windows версии 3.1), поэтому LibMain не может использоваться для регист­рации приложений.
Если приложение собирается использовать но зарегистрировать себя в библиотеке DDEML, вызвав специально предназначенную для этого функцию с именем DdeInitialize.
Прототип функции DdeInitialize определен в файле ddeml.h (ко­торый должен быть включен в исходный текст DDEML-приложения наряду с файлом windows.h):
UINT WINAPI DdeInitialize ( DWORD FAR* pidInst, // адрес идентификатора
из этих двух приложений будет сервером, а другое
действия подробнее.
DDEML, оно долж-
приложения
66
PFNCALLBACK pfnCallback, // адрес функции
обратного вызова DWORD afCmd, // флаги DWORD ulRes); // зарезервировано
Функция DdeInitialize используется в процессе инициализации и серверов, и клиентов DDEML. Сама по себе она не создает никаких каналов передачи данных между приложениями, однако процедура регистрации приложения, выполняемая этой функцией, должна быть проведена до вызова любых других функций, имеющих отношение к
DDEML.
Параметр pidInst представляет собой во, в которое после регистрации будет записан идентификатор, при­своенный копии приложения библиотекой DDEML (одновременно могут работать несколько копий одного и того же DDЕМL-прило­жения). Иными словами, в процессе регистрации библиотека DDEML присваивает копии приложения некоторый идентификатор, под ко­торым она его «знает». Вы должны указывать полученный от ции идентификатор при вызове всех остальных функций библиотеки
DDEML.
Перед вызовом функции DdeInitialize ваше приложение должно записать в двойное слово, адрес которого передается через первый параметр, нулевое значение.
Заметим, что идентификатор копии приложения, присвоенный в процессе регистрации, и идентификатор копии приложения, полу­ченный через параметр функции WinMain, – разные по смыслу (и по значению) идентификаторы.
Параметр pfnCallback представляет собой указатель на функцию обратного вызова, определенную приложением для обработки тран­закций. Как сервер, так и клиент должны определить такую функ­цию. Функция обратного вызова вызывается системой DDEML и содержит в себе всю логику обработки транзакций, определенную вами при разработке приложения.
Если приложение вызывает функцию DdeInitialize несколько раз
для многократной регистрации, каждый раз следует указывать отдельную функцию обратного вызова. Многократная регистрация вполне допустима, так как каждый раз библиотека DDEML будет создавать для себя новый идентификатор приложения. Такая мето­дика используется при создании DLL-библиотек, работающих с
DDEML. Обычным приложениям достаточно зарегистрировать себя
67
указатель на двойное сло-
функ-
один раз и, соответственно, определить одну функцию обратного вызова.
Через параметр afCmd передается двойное слово, каждый бит которого является флагом, определяющим режимы работы канала связи, а также влияющие на действия, выполняемые функцией
DdeInitialize.
Последний параметр с именем ulRes зарезервирован и должен иметь нулевое значение.
Приведем фрагмент кода, выполняющего регистрацию сервера в библиотеке DDEML:
idInst = 0L; lpDdeSrProc = MakeProcInstance((FARPROC)DDEServerCallback, hInst); if(DdeInitialize( (LPDWORD)&idInst, (PFNCALLBACK)lpDdeSrProc, APPCLASS_STANDARD, 0L)) { return FALSE; }
В этом фрагменте вначале создается переходник для функции обратного вызова, затем адрес этого переходника указывается во втором параметре функции DdeInitialize.
В случае успеха функция DdeInitialize возвращает нулевое значение. Для проверки можно также использовать константу DMLERR_NO_ERROR, определенную в файле ddeml.h. Если про­изошла ошибка, возвращается ненулевой код ошибки. Соответст­вующие константы определены имени DMLERR.
Символические константы с префиксом имени APPCLASS по­зволяют задать класс приложения с точки зрения использования
DDEML.
Класс APPCLASS_STANDARD предназначен для регистрации стандартного DDЕМL-приложения. Класс APPCLASS_MONITOR предназначен для отладчиков и других приложений, управляющих работой системы DDEML.
Символические константы с префиксом имени APPCMD по­зволяют конкретизировать функции, выполняемые приложением, и экономить
системные ресурсы. Если DDЕМL-приложение вы-
в файле ddeml.h и имеют префикс
68
полняет только функции клиента, следует указать флаг APPCMD_CLIENTONLY:
if(DdeInitialize((LPDWORD)&idInst, (PFNCALLBACK)lpDdeClProc, APPCMD_CLIENTONLY, 0L)) { return NULL; }
В простейших случаях можно ограничиться использованием класса APPCLASS_STANDARD при создании сервера DDEML и флага APPCMD_CLIENTONLY при создании клиента DDEML.
Если приложение больше не собирается работать с библиотекой DDEML, оно должно вызвать функцию DdeUninitialize, передав ей в качестве единственного параметра идентификатор копии приложе­ния, полученный от функции DdeInitialize:
BOOL WINAPI DdeUninitialize(DWORD idInst);
1.2.2. Регистрация сервиса
Следующий этап в инициализации сервера DDEML заключает­ся в регистрации предоставляемого им сервиса.
Библиотека DDEML использует трехступенчатую схему адре­сации данных, передаваемых по каналу связи, – сервис (service), раз­дел (topic) и элемент данных (data item). Приложение задает элемен­ты адреса в виде текстовых строк размером не более 255 байт. Это ограничение возникло в результате DDEML атомов, которые представляют собой идентификаторы тек­стовых строк, хранящихся в специальной системной таблице. Размер таких строк не должен превышать 255 байт.
Сервер DDEML может предоставлять сервис одного или не­скольких видов. Как правило, один сервер предоставляет только один сервис, причем текстовая строка, идентифицирующая сервис, часто совпадает с именем приложения. другую строку. Например, наше приложение DDEMLSR предостав­ляет сервис «BMPService». Как можно догадаться из названия, этот сервис связан с bmр-файлами (в действительности мы привели силь­но упрощенную версию сервера bmр-файлов, в которой для сокра-
использования для реализации
Но можно выбрать любую
69
щения объема листингов изъяты функции обслуживания bmр­файлов.
Второй элемент адреса – раздел. В рамках одного сервиса мож­но определить несколько разделов. Когда клиент DDEML создает канал с сервером, он указывает сервис и раздел. Раздел объединяет группу элементов данных или выполняемых функций. В приложе­нии DDEMLSR определен один раздел «BMPFile».
Канал DDEML служит для передачи блоков одного раздела сервер может обмениваться с клиентом разными блоками данных, каждый из которых идентифицируется при пере­даче именем элемента данных. В процессе создания канала связи не требуется указывать элементы данных.
Регистрация сервиса выполняется сервером DDEML обычно сразу после вызова функции DdeInitialize и выполняется в два этапа.
На первом этапе специальной системной таблице (таблице атомов), для чего вызыва­ется функция DdeCreateStringHandle:
HSZ WINAPI DdeCreateStringHandle(
DWORD idInst, // идентификатор приложения
LPCSTR psz, // адрес текстовой строки
int iCodePage); // кодовая страница
Через параметр idInst приложение должно передать идентифи­катор, полученный на этапе регистрации приложения в библиотеке DDEML функцией DdeInitialize.
Параметр psz представляет собой указатель на текстовую стро­ку, закрытую двоичным вышать 255 байт.
В качестве значения для параметра iCodePage можно указать СР_WINANSI (эта константа равна нулю). Можно также использо­вать значение, полученное от функции GetKBCodePage. Функция GetKBCodePage не имеет параметров и возвращает номер текущей кодовой страницы.
Идентификатор текстовой строки, возвращенный функцией DdeCreateStringHandle и соответствующий регистрируемому серви­су,
следует передать функции DdeNameService:
НDDЕDАТА WINAPI DdeNameService(
DWORD idInst, // идентификатор приложения
текстовая строка имени сервиса сохраняется в
нулем. Размер этой строки не должен пре-
70
данных. В рамках